diff options
author | mikhnenko <[email protected]> | 2024-06-25 08:50:35 +0300 |
---|---|---|
committer | mikhnenko <[email protected]> | 2024-06-25 09:00:27 +0300 |
commit | 509c9fc9e7b9c3b8be7307d72a4c966e5f9aa194 (patch) | |
tree | 4b8a6a44009906ac852e59efa0bc78bb12043a5b /contrib/libs/protoc/src/google/protobuf/compiler/python | |
parent | 7688f2313619a39a60ef3c2734d8efbc49a0a6db (diff) |
Update protobuf to 3.20.2 and pyprotobuf to 3.20.3
Если это pull-request что-то сломал, то:
- если это тест с канонизацией и еще нет pr с переканонизацией, то переканонизируйте пожалуйста сами
- проверьте, что тест не флапает
- приходите в [DEVTOOLSSUPPORT](https://st.yandex-team.ru/createTicket?queue=DEVTOOLSSUPPORT) - там вам обязательно помогут
987be5ed151f827f7f292f32420470b04b71a91d
Diffstat (limited to 'contrib/libs/protoc/src/google/protobuf/compiler/python')
6 files changed, 913 insertions, 244 deletions
diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.cc index ba79c259089..7c723febb38 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.cc +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.cc @@ -54,13 +54,15 @@ #include <google/protobuf/stubs/logging.h> #include <google/protobuf/stubs/common.h> -#include <google/protobuf/stubs/stringprintf.h> -#include <google/protobuf/descriptor.pb.h> +#include <google/protobuf/compiler/python/python_helpers.h> +#include <google/protobuf/compiler/python/python_pyi_generator.h> #include <google/protobuf/io/printer.h> #include <google/protobuf/io/zero_copy_stream.h> #include <google/protobuf/descriptor.h> #include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/stubs/stringprintf.h> #include <google/protobuf/stubs/substitute.h> +#include <google/protobuf/descriptor.pb.h> namespace google { namespace protobuf { @@ -68,22 +70,6 @@ namespace compiler { namespace python { namespace { - -TProtoStringType FixEv(const TProtoStringType& filename) { - if (HasSuffixString(filename, ".ev")) { - return StripSuffixString(filename, ".ev") + "_ev.proto"; - } - return filename; -} - -// Returns the Python module name expected for a given .proto filename. -TProtoStringType ModuleName(const TProtoStringType& filename) { - TProtoStringType basename = StripProto(FixEv(filename)); - ReplaceCharacters(&basename, "-", '_'); - ReplaceCharacters(&basename, "/", '.'); - return basename + "_pb2"; -} - // Returns the alias we assign to the module of the given .proto filename // when importing. See testPackageInitializationImport in // net/proto2/python/internal/reflection_test.py @@ -98,78 +84,18 @@ TProtoStringType ModuleAlias(const TProtoStringType& filename) { return module_name; } -// Keywords reserved by the Python language. -const char* const kKeywords[] = { - "False", "None", "True", "and", "as", "assert", - "async", "await", "break", "class", "continue", "def", - "del", "elif", "else", "except", "finally", "for", - "from", "global", "if", "import", "in", "is", - "lambda", "nonlocal", "not", "or", "pass", "raise", - "return", "try", "while", "with", "yield", "print", -}; -const char* const* kKeywordsEnd = - kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0])); - -bool ContainsPythonKeyword(const TProtoStringType& module_name) { - std::vector<TProtoStringType> tokens = Split(module_name, "."); - for (int i = 0; i < tokens.size(); ++i) { - if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) { - return true; - } - } - return false; -} - -inline bool IsPythonKeyword(const TProtoStringType& name) { - return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd); -} - -TProtoStringType ResolveKeyword(const TProtoStringType& name) { - if (IsPythonKeyword(name)) { - return "globals()['" + name + "']"; - } - return name; -} - -// Returns the name of all containing types for descriptor, -// in order from outermost to innermost, followed by descriptor's -// own name. Each name is separated by |separator|. -template <typename DescriptorT> -TProtoStringType NamePrefixedWithNestedTypes(const DescriptorT& descriptor, - const TProtoStringType& separator) { - TProtoStringType name = descriptor.name(); - const Descriptor* parent = descriptor.containing_type(); - if (parent != nullptr) { - TProtoStringType prefix = NamePrefixedWithNestedTypes(*parent, separator); - if (separator == "." && IsPythonKeyword(name)) { - return "getattr(" + prefix + ", '" + name + "')"; - } else { - return prefix + separator + name; - } - } - if (separator == ".") { - name = ResolveKeyword(name); - } - return name; -} - // Name of the class attribute where we store the Python // descriptor.Descriptor instance for the generated class. // Must stay consistent with the _DESCRIPTOR_KEY constant // in proto2/public/reflection.py. 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 && file->options().py_generic_services(); -} - -// Prints the common boilerplate needed at the top of every .py // file output by this generator. void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file, bool descriptor_proto) { @@ -180,27 +106,16 @@ void PrintTopBoilerplate(io::Printer* printer, const FileDescriptor* file, "# source: $filename$\n" "\"\"\"Generated protocol buffer code.\"\"\"\n", "filename", file->name()); - if (HasTopLevelEnums(file)) { - printer->Print( - "from google.protobuf.internal import enum_type_wrapper\n"); - } printer->Print( + "from google.protobuf.internal import builder as _builder\n" "from google.protobuf import descriptor as _descriptor\n" "from google.protobuf import descriptor_pool as " "_descriptor_pool\n" - "from google.protobuf import message as _message\n" - "from google.protobuf import reflection as _reflection\n" "from google.protobuf import symbol_database as " "_symbol_database\n"); - if (HasGenericServices(file)) { - printer->Print( - "from google.protobuf import service as _service\n" - "from google.protobuf import service_reflection\n"); - } - printer->Print( - "# @@protoc_insertion_point(imports)\n\n" - "_sym_db = _symbol_database.Default()\n"); + printer->Print("# @@protoc_insertion_point(imports)\n\n"); + printer->Print("_sym_db = _symbol_database.Default()\n"); printer->Print("\n\n"); } @@ -315,6 +230,11 @@ bool Generator::Generate(const FileDescriptor* file, for (int i = 0; i < options.size(); i++) { if (options[i].first == "cpp_generated_lib_linked") { cpp_generated_lib_linked = true; + } else if (options[i].first == "pyi_out") { + python::PyiGenerator pyi_generator; + if (!pyi_generator.Generate(file, "", context, error)) { + return false; + } } else { *error = "Unknown generator option: " + options[i].first; return false; @@ -330,11 +250,8 @@ bool Generator::Generate(const FileDescriptor* file, // to have any mutable members. Then it is implicitly thread-safe. MutexLock lock(&mutex_); file_ = file; - TProtoStringType module_name = ModuleName(file->name()); - TProtoStringType filename = module_name; - ReplaceCharacters(&filename, ".", '/'); - filename += ".py"; + TProtoStringType filename = GetFileName(file, ".py"); pure_python_workable_ = !cpp_generated_lib_linked; if (HasPrefixString(file->name(), "google/protobuf/")) { pure_python_workable_ = true; @@ -355,15 +272,13 @@ bool Generator::Generate(const FileDescriptor* file, PrintImports(); } PrintFileDescriptor(); - PrintTopLevelEnums(); - PrintTopLevelExtensions(); if (pure_python_workable_) { if (GeneratingDescriptorProto()) { printer_->Print("if _descriptor._USE_C_DESCRIPTORS == False:\n"); printer_->Indent(); // Create enums before message descriptors - PrintAllNestedEnumsInFile(StripPrintDescriptor::kCreate); - PrintMessageDescriptors(StripPrintDescriptor::kCreate); + PrintAllNestedEnumsInFile(); + PrintMessageDescriptors(); FixForeignFieldsInDescriptors(); printer_->Outdent(); printer_->Print("else:\n"); @@ -371,16 +286,18 @@ bool Generator::Generate(const FileDescriptor* file, } // Find the message descriptors first and then use the message // descriptor to find enums. - PrintMessageDescriptors(StripPrintDescriptor::kFind); - PrintAllNestedEnumsInFile(StripPrintDescriptor::kFind); + printer_->Print( + "_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, globals())\n"); if (GeneratingDescriptorProto()) { printer_->Outdent(); } } - PrintMessages(); + TProtoStringType module_name = ModuleName(file->name()); + printer_->Print( + "_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, '$module_name$', " + "globals())\n", + "module_name", module_name); if (pure_python_workable_) { - PrintServiceDescriptors(); - printer.Print("if _descriptor._USE_C_DESCRIPTORS == False:\n"); printer_->Indent(); @@ -401,7 +318,9 @@ bool Generator::Generate(const FileDescriptor* file, printer_->Outdent(); } if (HasGenericServices(file)) { - PrintServices(); + printer_->Print( + "_builder.BuildServices(DESCRIPTOR, '$module_name$', globals())\n", + "module_name", module_name); } printer.Print("# @@protoc_insertion_point(module_scope)\n"); @@ -409,7 +328,6 @@ bool Generator::Generate(const FileDescriptor* file, return !printer.failed(); } - // Prints Python imports for all modules imported by |file|. void Generator::PrintImports() const { for (int i = 0; i < file_->dependency_count(); ++i) { @@ -522,47 +440,17 @@ void Generator::PrintFileDescriptor() const { printer_->Print("\n"); } -// Prints descriptors and module-level constants for all top-level -// enums defined in |file|. -void Generator::PrintTopLevelEnums() const { - std::vector<std::pair<TProtoStringType, int> > top_level_enum_values; - for (int i = 0; i < file_->enum_type_count(); ++i) { - const EnumDescriptor& enum_descriptor = *file_->enum_type(i); - PrintFindEnum(enum_descriptor); - printer_->Print( - "$name$ = " - "enum_type_wrapper.EnumTypeWrapper($descriptor_name$)", - "name", ResolveKeyword(enum_descriptor.name()), "descriptor_name", - ModuleLevelDescriptorName(enum_descriptor)); - printer_->Print("\n"); - - for (int j = 0; j < enum_descriptor.value_count(); ++j) { - const EnumValueDescriptor& value_descriptor = *enum_descriptor.value(j); - top_level_enum_values.push_back( - std::make_pair(value_descriptor.name(), value_descriptor.number())); - } - } - - for (int i = 0; i < top_level_enum_values.size(); ++i) { - printer_->Print("$name$ = $value$\n", "name", - ResolveKeyword(top_level_enum_values[i].first), "value", - StrCat(top_level_enum_values[i].second)); - } - printer_->Print("\n"); -} - // Prints all enums contained in all message types in |file|. -void Generator::PrintAllNestedEnumsInFile( - StripPrintDescriptor print_mode) const { +void Generator::PrintAllNestedEnumsInFile() const { for (int i = 0; i < file_->message_type_count(); ++i) { - PrintNestedEnums(*file_->message_type(i), print_mode); + PrintNestedEnums(*file_->message_type(i)); } } // Prints a Python statement assigning the appropriate module-level // enum name to a Python EnumDescriptor object equivalent to // enum_descriptor. -void Generator::PrintCreateEnum(const EnumDescriptor& enum_descriptor) const { +void Generator::PrintEnum(const EnumDescriptor& enum_descriptor) const { std::map<TProtoStringType, TProtoStringType> m; TProtoStringType module_level_descriptor_name = ModuleLevelDescriptorName(enum_descriptor); @@ -606,68 +494,23 @@ void Generator::PrintCreateEnum(const EnumDescriptor& enum_descriptor) const { printer_->Print("\n"); } -void Generator::PrintFindEnum(const EnumDescriptor& enum_descriptor) const { - std::map<TProtoStringType, TProtoStringType> m; - m["descriptor_name"] = ModuleLevelDescriptorName(enum_descriptor); - m["name"] = enum_descriptor.name(); - m["file"] = kDescriptorKey; - if (enum_descriptor.containing_type()) { - m["containing_type"] = - ModuleLevelDescriptorName(*enum_descriptor.containing_type()); - printer_->Print(m, - "$descriptor_name$ = " - "$containing_type$.enum_types_by_name['$name$']\n"); - } else { - printer_->Print( - m, "$descriptor_name$ = $file$.enum_types_by_name['$name$']\n"); - } -} - // Recursively prints enums in nested types within descriptor, then // prints enums contained at the top level in descriptor. -void Generator::PrintNestedEnums(const Descriptor& descriptor, - StripPrintDescriptor print_mode) const { +void Generator::PrintNestedEnums(const Descriptor& descriptor) const { for (int i = 0; i < descriptor.nested_type_count(); ++i) { - PrintNestedEnums(*descriptor.nested_type(i), print_mode); + PrintNestedEnums(*descriptor.nested_type(i)); } for (int i = 0; i < descriptor.enum_type_count(); ++i) { - if (print_mode == StripPrintDescriptor::kCreate) { - PrintCreateEnum(*descriptor.enum_type(i)); - } else { - PrintFindEnum(*descriptor.enum_type(i)); - } + PrintEnum(*descriptor.enum_type(i)); } } -void Generator::PrintTopLevelExtensions() const { - for (int i = 0; i < file_->extension_count(); ++i) { - const FieldDescriptor& extension_field = *file_->extension(i); - TProtoStringType constant_name = extension_field.name() + "_FIELD_NUMBER"; - ToUpper(&constant_name); - printer_->Print("$constant_name$ = $number$\n", "constant_name", - constant_name, "number", - StrCat(extension_field.number())); - printer_->Print( - "$resolved_name$ = " - "$file$.extensions_by_name['$name$']\n", - "resolved_name", ResolveKeyword(extension_field.name()), "file", - kDescriptorKey, "name", extension_field.name()); - } - printer_->Print("\n"); -} - // Prints Python equivalents of all Descriptors in |file|. -void Generator::PrintMessageDescriptors(StripPrintDescriptor print_mode) const { - if (print_mode == StripPrintDescriptor::kCreate) { - for (int i = 0; i < file_->message_type_count(); ++i) { - PrintCreateDescriptor(*file_->message_type(i)); - printer_->Print("\n"); - } - } else { - for (int i = 0; i < file_->message_type_count(); ++i) { - PrintFindDescriptor(*file_->message_type(i)); - } +void Generator::PrintMessageDescriptors() const { + for (int i = 0; i < file_->message_type_count(); ++i) { + PrintDescriptor(*file_->message_type(i)); + printer_->Print("\n"); } } @@ -736,14 +579,13 @@ void Generator::PrintServiceStub(const ServiceDescriptor& descriptor) const { // to a Python Descriptor object for message_descriptor. // // Mutually recursive with PrintNestedDescriptors(). -void Generator::PrintCreateDescriptor( - const Descriptor& message_descriptor) const { +void Generator::PrintDescriptor(const Descriptor& message_descriptor) const { std::map<TProtoStringType, TProtoStringType> m; m["name"] = message_descriptor.name(); m["full_name"] = message_descriptor.full_name(); m["file"] = kDescriptorKey; - PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kCreate); + PrintNestedDescriptors(message_descriptor); printer_->Print("\n"); printer_->Print("$descriptor_name$ = _descriptor.Descriptor(\n", @@ -829,41 +671,14 @@ void Generator::PrintCreateDescriptor( printer_->Print(")\n"); } -void Generator::PrintFindDescriptor( - const Descriptor& message_descriptor) const { - std::map<TProtoStringType, TProtoStringType> m; - m["descriptor_name"] = ModuleLevelDescriptorName(message_descriptor); - m["name"] = message_descriptor.name(); - - if (message_descriptor.containing_type()) { - m["containing_type"] = - ModuleLevelDescriptorName(*message_descriptor.containing_type()); - printer_->Print(m, - "$descriptor_name$ = " - "$containing_type$.nested_types_by_name['$name$']\n"); - } else { - m["file"] = kDescriptorKey; - printer_->Print( - m, "$descriptor_name$ = $file$.message_types_by_name['$name$']\n"); - } - - PrintNestedDescriptors(message_descriptor, StripPrintDescriptor::kFind); -} - // Prints Python Descriptor objects for all nested types contained in // message_descriptor. // // Mutually recursive with PrintDescriptor(). -void Generator::PrintNestedDescriptors(const Descriptor& containing_descriptor, - StripPrintDescriptor print_mode) const { - if (print_mode == StripPrintDescriptor::kCreate) { - for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { - PrintCreateDescriptor(*containing_descriptor.nested_type(i)); - } - } else { - for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { - PrintFindDescriptor(*containing_descriptor.nested_type(i)); - } +void Generator::PrintNestedDescriptors( + const Descriptor& containing_descriptor) const { + for (int i = 0; i < containing_descriptor.nested_type_count(); ++i) { + PrintDescriptor(*containing_descriptor.nested_type(i)); } } @@ -1469,7 +1284,7 @@ void Generator::FixOptionsForEnum(const EnumDescriptor& enum_descriptor) const { if (value_options != "None") { PrintDescriptorOptionsFixingCode( StringPrintf("%s.values_by_name[\"%s\"]", descriptor_name.c_str(), - value_descriptor.name().c_str()), + value_descriptor.name().c_str()), value_options, printer_); } } diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.h index d5af959fceb..359d802aeea 100644 --- a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.h +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_generator.h @@ -40,6 +40,7 @@ #include <google/protobuf/compiler/code_generator.h> #include <google/protobuf/stubs/mutex.h> +// Must be included last. #include <google/protobuf/port_def.inc> namespace google { @@ -59,8 +60,6 @@ class Printer; namespace compiler { namespace python { -enum class StripPrintDescriptor { kCreate, kFind }; - // CodeGenerator implementation for generated Python protocol buffer classes. // If you create your own protocol compiler binary and you want it to support // Python output, you can do so by registering an instance of this @@ -68,7 +67,7 @@ enum class StripPrintDescriptor { kCreate, kFind }; class PROTOC_EXPORT Generator : public CodeGenerator { public: Generator(); - virtual ~Generator(); + ~Generator() override; // CodeGenerator methods. bool Generate(const FileDescriptor* file, const TProtoStringType& parameter, @@ -80,14 +79,9 @@ class PROTOC_EXPORT Generator : public CodeGenerator { private: void PrintImports() const; void PrintFileDescriptor() const; - void PrintTopLevelEnums() const; - void PrintAllNestedEnumsInFile(StripPrintDescriptor print_mode) const; - void PrintNestedEnums(const Descriptor& descriptor, - StripPrintDescriptor print_mode) const; - void PrintCreateEnum(const EnumDescriptor& enum_descriptor) const; - void PrintFindEnum(const EnumDescriptor& enum_descriptor) const; - - void PrintTopLevelExtensions() const; + void PrintAllNestedEnumsInFile() const; + void PrintNestedEnums(const Descriptor& descriptor) const; + void PrintEnum(const EnumDescriptor& enum_descriptor) const; void PrintFieldDescriptor(const FieldDescriptor& field, bool is_extension) const; @@ -97,11 +91,9 @@ class PROTOC_EXPORT Generator : public CodeGenerator { const FieldDescriptor* (Descriptor::*GetterFn)(int)const) const; void PrintFieldsInDescriptor(const Descriptor& message_descriptor) const; void PrintExtensionsInDescriptor(const Descriptor& message_descriptor) const; - void PrintMessageDescriptors(StripPrintDescriptor print_mode) const; - void PrintCreateDescriptor(const Descriptor& message_descriptor) const; - void PrintFindDescriptor(const Descriptor& message_descriptor) const; - void PrintNestedDescriptors(const Descriptor& containing_descriptor, - StripPrintDescriptor print_mode) const; + void PrintMessageDescriptors() const; + void PrintDescriptor(const Descriptor& message_descriptor) const; + void PrintNestedDescriptors(const Descriptor& containing_descriptor) const; void PrintMessages() const; void PrintMessage(const Descriptor& message_descriptor, diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.cc b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.cc new file mode 100644 index 00000000000..7a9721c02ca --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.cc @@ -0,0 +1,138 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/compiler/python/python_helpers.h> + +#include <algorithm> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { + +TProtoStringType FixEv(const TProtoStringType& filename) { + if (HasSuffixString(filename, ".ev")) { + return StripSuffixString(filename, ".ev") + "_ev.proto"; + } + return filename; +} + +// Returns the Python module name expected for a given .proto filename. +TProtoStringType ModuleName(const TProtoStringType& filename) { + TProtoStringType basename = StripProto(FixEv(filename)); + ReplaceCharacters(&basename, "-", '_'); + ReplaceCharacters(&basename, "/", '.'); + return basename + "_pb2"; +} + +TProtoStringType StrippedModuleName(const TProtoStringType& filename) { + TProtoStringType module_name = ModuleName(filename); + return module_name; +} + +// Keywords reserved by the Python language. +const char* const kKeywords[] = { + "False", "None", "True", "and", "as", "assert", + "async", "await", "break", "class", "continue", "def", + "del", "elif", "else", "except", "finally", "for", + "from", "global", "if", "import", "in", "is", + "lambda", "nonlocal", "not", "or", "pass", "raise", + "return", "try", "while", "with", "yield", "print", +}; +const char* const* kKeywordsEnd = + kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0])); + +bool ContainsPythonKeyword(const TProtoStringType& module_name) { + std::vector<TProtoStringType> tokens = Split(module_name, "."); + for (int i = 0; i < static_cast<int>(tokens.size()); ++i) { + if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) { + return true; + } + } + return false; +} + +bool IsPythonKeyword(const TProtoStringType& name) { + return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd); +} + +TProtoStringType ResolveKeyword(const TProtoStringType& name) { + if (IsPythonKeyword(name)) { + return "globals()['" + name + "']"; + } + return name; +} + +TProtoStringType GetFileName(const FileDescriptor* file_des, + const TProtoStringType& suffix) { + TProtoStringType module_name = ModuleName(file_des->name()); + TProtoStringType filename = module_name; + ReplaceCharacters(&filename, ".", '/'); + filename += suffix; + return filename; +} + +bool HasGenericServices(const FileDescriptor* file) { + return file->service_count() > 0 && file->options().py_generic_services(); +} + +template <typename DescriptorT> +TProtoStringType NamePrefixedWithNestedTypes(const DescriptorT& descriptor, + const TProtoStringType& separator) { + TProtoStringType name = descriptor.name(); + const Descriptor* parent = descriptor.containing_type(); + if (parent != nullptr) { + TProtoStringType prefix = NamePrefixedWithNestedTypes(*parent, separator); + if (separator == "." && IsPythonKeyword(name)) { + return "getattr(" + prefix + ", '" + name + "')"; + } else { + return prefix + separator + name; + } + } + if (separator == ".") { + name = ResolveKeyword(name); + } + return name; +} + +template TProtoStringType NamePrefixedWithNestedTypes<Descriptor>( + const Descriptor& descriptor, const TProtoStringType& separator); +template TProtoStringType NamePrefixedWithNestedTypes<EnumDescriptor>( + const EnumDescriptor& descriptor, const TProtoStringType& separator); + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.h b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.h new file mode 100644 index 00000000000..8745698acf6 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_helpers.h @@ -0,0 +1,62 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__ +#define GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__ + +#include <string> + +#include <google/protobuf/descriptor.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { + + +TProtoStringType ModuleName(const TProtoStringType& filename); +TProtoStringType StrippedModuleName(const TProtoStringType& filename); +bool ContainsPythonKeyword(const TProtoStringType& module_name); +bool IsPythonKeyword(const TProtoStringType& name); +TProtoStringType ResolveKeyword(const TProtoStringType& name); +TProtoStringType GetFileName(const FileDescriptor* file_des, + const TProtoStringType& suffix); +bool HasGenericServices(const FileDescriptor* file); + +template <typename DescriptorT> +TProtoStringType NamePrefixedWithNestedTypes(const DescriptorT& descriptor, + const TProtoStringType& separator); + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google + +#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_HELPERS_H__ diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.cc b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.cc new file mode 100644 index 00000000000..89cfbf86fe6 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.cc @@ -0,0 +1,558 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include <google/protobuf/compiler/python/python_pyi_generator.h> + +#include <string> + +#include <google/protobuf/compiler/python/python_helpers.h> +#include <google/protobuf/io/printer.h> +#include <google/protobuf/io/zero_copy_stream.h> +#include <google/protobuf/descriptor.h> +#include <google/protobuf/stubs/strutil.h> +#include <google/protobuf/descriptor.pb.h> + +namespace google { +namespace protobuf { +namespace compiler { +namespace python { + +template <typename DescriptorT> +struct SortByName { + bool operator()(const DescriptorT* l, const DescriptorT* r) const { + return l->name() < r->name(); + } +}; + +PyiGenerator::PyiGenerator() : file_(nullptr) {} + +PyiGenerator::~PyiGenerator() {} + +void PyiGenerator::PrintItemMap( + const std::map<TProtoStringType, TProtoStringType>& item_map) const { + for (const auto& entry : item_map) { + printer_->Print("$key$: $value$\n", "key", entry.first, "value", + entry.second); + } +} + +template <typename DescriptorT> +TProtoStringType PyiGenerator::ModuleLevelName(const DescriptorT& descriptor) const { + TProtoStringType name = NamePrefixedWithNestedTypes(descriptor, "."); + if (descriptor.file() != file_) { + TProtoStringType module_name = ModuleName(descriptor.file()->name()); + std::vector<TProtoStringType> tokens = Split(module_name, "."); + name = "_" + tokens.back() + "." + name; + } + return name; +} + +struct ImportModules { + bool has_repeated = false; // _containers + bool has_iterable = false; // typing.Iterable + bool has_messages = false; // _message + bool has_enums = false; // _enum_type_wrapper + bool has_extendable = false; // _python_message + bool has_mapping = false; // typing.Mapping + bool has_optional = false; // typing.Optional + bool has_union = false; // typing.Uion +}; + +// Checks what modules should be imported for this message +// descriptor. +void CheckImportModules(const Descriptor* descriptor, + ImportModules* import_modules) { + if (descriptor->extension_range_count() > 0) { + import_modules->has_extendable = true; + } + if (descriptor->enum_type_count() > 0) { + import_modules->has_enums = true; + } + for (int i = 0; i < descriptor->field_count(); ++i) { + const FieldDescriptor* field = descriptor->field(i); + if (IsPythonKeyword(field->name())) { + continue; + } + import_modules->has_optional = true; + if (field->is_repeated()) { + import_modules->has_repeated = true; + } + if (field->is_map()) { + import_modules->has_mapping = true; + const FieldDescriptor* value_des = field->message_type()->field(1); + if (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE || + value_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + import_modules->has_union = true; + } + } else { + if (field->is_repeated()) { + import_modules->has_iterable = true; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + import_modules->has_union = true; + import_modules->has_mapping = true; + } + if (field->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + import_modules->has_union = true; + } + } + } + for (int i = 0; i < descriptor->nested_type_count(); ++i) { + CheckImportModules(descriptor->nested_type(i), import_modules); + } +} + +void PyiGenerator::PrintImports( + std::map<TProtoStringType, TProtoStringType>* item_map) const { + // Prints imported dependent _pb2 files. + for (int i = 0; i < file_->dependency_count(); ++i) { + const TProtoStringType& filename = file_->dependency(i)->name(); + TProtoStringType module_name = StrippedModuleName(filename); + size_t last_dot_pos = module_name.rfind('.'); + TProtoStringType import_statement; + if (last_dot_pos == TProtoStringType::npos) { + import_statement = "import " + module_name; + } else { + import_statement = "from " + module_name.substr(0, last_dot_pos) + + " import " + module_name.substr(last_dot_pos + 1); + module_name = module_name.substr(last_dot_pos + 1); + } + printer_->Print("$statement$ as _$module_name$\n", "statement", + import_statement, "module_name", module_name); + } + + // Checks what modules should be imported. + ImportModules import_modules; + if (file_->message_type_count() > 0) { + import_modules.has_messages = true; + } + if (file_->enum_type_count() > 0) { + import_modules.has_enums = true; + } + for (int i = 0; i < file_->message_type_count(); i++) { + CheckImportModules(file_->message_type(i), &import_modules); + } + + // Prints modules (e.g. _containers, _messages, typing) that are + // required in the proto file. + if (import_modules.has_repeated) { + printer_->Print( + "from google.protobuf.internal import containers as " + "_containers\n"); + } + if (import_modules.has_enums) { + printer_->Print( + "from google.protobuf.internal import enum_type_wrapper" + " as _enum_type_wrapper\n"); + } + if (import_modules.has_extendable) { + printer_->Print( + "from google.protobuf.internal import python_message" + " as _python_message\n"); + } + printer_->Print( + "from google.protobuf import" + " descriptor as _descriptor\n"); + if (import_modules.has_messages) { + printer_->Print( + "from google.protobuf import message as _message\n"); + } + if (HasGenericServices(file_)) { + printer_->Print( + "from google.protobuf import service as" + " _service\n"); + } + printer_->Print("from typing import "); + printer_->Print("ClassVar"); + if (import_modules.has_iterable) { + printer_->Print(", Iterable"); + } + if (import_modules.has_mapping) { + printer_->Print(", Mapping"); + } + if (import_modules.has_optional) { + printer_->Print(", Optional"); + } + if (file_->service_count() > 0) { + printer_->Print(", Text"); + } + if (import_modules.has_union) { + printer_->Print(", Union"); + } + printer_->Print("\n\n"); + + // Public imports + for (int i = 0; i < file_->public_dependency_count(); ++i) { + const FileDescriptor* public_dep = file_->public_dependency(i); + TProtoStringType module_name = StrippedModuleName(public_dep->name()); + // Top level messages in public imports + for (int i = 0; i < public_dep->message_type_count(); ++i) { + printer_->Print("from $module$ import $message_class$\n", "module", + module_name, "message_class", + public_dep->message_type(i)->name()); + } + // Top level enums for public imports + for (int i = 0; i < public_dep->enum_type_count(); ++i) { + printer_->Print("from $module$ import $enum_class$\n", "module", + module_name, "enum_class", + public_dep->enum_type(i)->name()); + } + // Enum values for public imports + for (int i = 0; i < public_dep->enum_type_count(); ++i) { + const EnumDescriptor* enum_descriptor = public_dep->enum_type(i); + for (int j = 0; j < enum_descriptor->value_count(); ++j) { + (*item_map)[enum_descriptor->value(j)->name()] = + ModuleLevelName(*enum_descriptor); + } + } + // Top level extensions for public imports + AddExtensions(*public_dep, item_map); + } +} + +void PyiGenerator::PrintEnum(const EnumDescriptor& enum_descriptor) const { + TProtoStringType enum_name = enum_descriptor.name(); + printer_->Print( + "class $enum_name$(int, metaclass=_enum_type_wrapper.EnumTypeWrapper):\n" + " __slots__ = []\n", + "enum_name", enum_name); +} + +// Adds enum value to item map which will be ordered and printed later. +void PyiGenerator::AddEnumValue( + const EnumDescriptor& enum_descriptor, + std::map<TProtoStringType, TProtoStringType>* item_map) const { + // enum values + TProtoStringType module_enum_name = ModuleLevelName(enum_descriptor); + for (int j = 0; j < enum_descriptor.value_count(); ++j) { + const EnumValueDescriptor* value_descriptor = enum_descriptor.value(j); + (*item_map)[value_descriptor->name()] = module_enum_name; + } +} + +// Prints top level enums +void PyiGenerator::PrintTopLevelEnums() const { + for (int i = 0; i < file_->enum_type_count(); ++i) { + printer_->Print("\n"); + PrintEnum(*file_->enum_type(i)); + } +} + +// Add top level extensions to item_map which will be ordered and +// printed later. +template <typename DescriptorT> +void PyiGenerator::AddExtensions( + const DescriptorT& descriptor, + std::map<TProtoStringType, TProtoStringType>* item_map) const { + for (int i = 0; i < descriptor.extension_count(); ++i) { + const FieldDescriptor* extension_field = descriptor.extension(i); + TProtoStringType constant_name = extension_field->name() + "_FIELD_NUMBER"; + ToUpper(&constant_name); + (*item_map)[constant_name] = "ClassVar[int]"; + (*item_map)[extension_field->name()] = "_descriptor.FieldDescriptor"; + } +} + +// Returns the string format of a field's cpp_type +TProtoStringType PyiGenerator::GetFieldType(const FieldDescriptor& field_des) const { + switch (field_des.cpp_type()) { + case FieldDescriptor::CPPTYPE_INT32: + case FieldDescriptor::CPPTYPE_UINT32: + case FieldDescriptor::CPPTYPE_INT64: + case FieldDescriptor::CPPTYPE_UINT64: + return "int"; + case FieldDescriptor::CPPTYPE_DOUBLE: + case FieldDescriptor::CPPTYPE_FLOAT: + return "float"; + case FieldDescriptor::CPPTYPE_BOOL: + return "bool"; + case FieldDescriptor::CPPTYPE_ENUM: + return ModuleLevelName(*field_des.enum_type()); + case FieldDescriptor::CPPTYPE_STRING: + if (field_des.type() == FieldDescriptor::TYPE_STRING) { + return "str"; + } else { + return "bytes"; + } + case FieldDescriptor::CPPTYPE_MESSAGE: + return ModuleLevelName(*field_des.message_type()); + default: + GOOGLE_LOG(FATAL) << "Unsuppoted field type."; + } + return ""; +} + +void PyiGenerator::PrintMessage(const Descriptor& message_descriptor, + bool is_nested) const { + if (!is_nested) { + printer_->Print("\n"); + } + TProtoStringType class_name = message_descriptor.name(); + printer_->Print("class $class_name$(_message.Message):\n", "class_name", + class_name); + printer_->Indent(); + printer_->Indent(); + + std::vector<const FieldDescriptor*> fields; + fields.reserve(message_descriptor.field_count()); + for (int i = 0; i < message_descriptor.field_count(); ++i) { + fields.push_back(message_descriptor.field(i)); + } + std::sort(fields.begin(), fields.end(), SortByName<FieldDescriptor>()); + + // Prints slots + printer_->Print("__slots__ = [", "class_name", class_name); + bool first_item = true; + for (const auto& field_des : fields) { + if (IsPythonKeyword(field_des->name())) { + continue; + } + if (first_item) { + first_item = false; + } else { + printer_->Print(", "); + } + printer_->Print("\"$field_name$\"", "field_name", field_des->name()); + } + printer_->Print("]\n"); + + std::map<TProtoStringType, TProtoStringType> item_map; + // Prints Extensions for extendable messages + if (message_descriptor.extension_range_count() > 0) { + item_map["Extensions"] = "_python_message._ExtensionDict"; + } + + // Prints nested enums + std::vector<const EnumDescriptor*> nested_enums; + nested_enums.reserve(message_descriptor.enum_type_count()); + for (int i = 0; i < message_descriptor.enum_type_count(); ++i) { + nested_enums.push_back(message_descriptor.enum_type(i)); + } + std::sort(nested_enums.begin(), nested_enums.end(), + SortByName<EnumDescriptor>()); + + for (const auto& entry : nested_enums) { + PrintEnum(*entry); + // Adds enum value to item_map which will be ordered and printed later + AddEnumValue(*entry, &item_map); + } + + // Prints nested messages + std::vector<const Descriptor*> nested_messages; + nested_messages.reserve(message_descriptor.nested_type_count()); + for (int i = 0; i < message_descriptor.nested_type_count(); ++i) { + nested_messages.push_back(message_descriptor.nested_type(i)); + } + std::sort(nested_messages.begin(), nested_messages.end(), + SortByName<Descriptor>()); + + for (const auto& entry : nested_messages) { + PrintMessage(*entry, true); + } + + // Adds extensions to item_map which will be ordered and printed later + AddExtensions(message_descriptor, &item_map); + + // Adds field number and field descriptor to item_map + for (int i = 0; i < message_descriptor.field_count(); ++i) { + const FieldDescriptor& field_des = *message_descriptor.field(i); + item_map[ToUpper(field_des.name()) + "_FIELD_NUMBER"] = + "ClassVar[int]"; + if (IsPythonKeyword(field_des.name())) { + continue; + } + TProtoStringType field_type = ""; + if (field_des.is_map()) { + const FieldDescriptor* key_des = field_des.message_type()->field(0); + const FieldDescriptor* value_des = field_des.message_type()->field(1); + field_type = (value_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? "_containers.MessageMap[" + : "_containers.ScalarMap["); + field_type += GetFieldType(*key_des); + field_type += ", "; + field_type += GetFieldType(*value_des); + } else { + if (field_des.is_repeated()) { + field_type = (field_des.cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE + ? "_containers.RepeatedCompositeFieldContainer[" + : "_containers.RepeatedScalarFieldContainer["); + } + field_type += GetFieldType(field_des); + } + + if (field_des.is_repeated()) { + field_type += "]"; + } + item_map[field_des.name()] = field_type; + } + + // Prints all items in item_map + PrintItemMap(item_map); + + // Prints __init__ + printer_->Print("def __init__(self"); + bool has_key_words = false; + bool is_first = true; + for (int i = 0; i < message_descriptor.field_count(); ++i) { + const FieldDescriptor* field_des = message_descriptor.field(i); + if (IsPythonKeyword(field_des->name())) { + has_key_words = true; + continue; + } + TProtoStringType field_name = field_des->name(); + if (is_first && field_name == "self") { + // See b/144146793 for an example of real code that generates a (self, + // self) method signature. Since repeating a parameter name is illegal in + // Python, we rename the duplicate self. + field_name = "self_"; + } + is_first = false; + printer_->Print(", $field_name$: ", "field_name", field_name); + if (field_des->is_repeated() || + field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) { + printer_->Print("Optional["); + } + if (field_des->is_map()) { + const Descriptor* map_entry = field_des->message_type(); + printer_->Print("Mapping[$key_type$, $value_type$]", "key_type", + GetFieldType(*map_entry->field(0)), "value_type", + GetFieldType(*map_entry->field(1))); + } else { + if (field_des->is_repeated()) { + printer_->Print("Iterable["); + } + if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE) { + printer_->Print("Union[$type_name$, Mapping]", "type_name", + GetFieldType(*field_des)); + } else { + if (field_des->cpp_type() == FieldDescriptor::CPPTYPE_ENUM) { + printer_->Print("Union[$type_name$, str]", "type_name", + ModuleLevelName(*field_des->enum_type())); + } else { + printer_->Print("$type_name$", "type_name", GetFieldType(*field_des)); + } + } + if (field_des->is_repeated()) { + printer_->Print("]"); + } + } + if (field_des->is_repeated() || + field_des->cpp_type() != FieldDescriptor::CPPTYPE_BOOL) { + printer_->Print("]"); + } + printer_->Print(" = ..."); + } + if (has_key_words) { + printer_->Print(", **kwargs"); + } + printer_->Print(") -> None: ...\n"); + + printer_->Outdent(); + printer_->Outdent(); +} + +void PyiGenerator::PrintMessages() const { + // Order the descriptors by name to have same output with proto_to_pyi.py + std::vector<const Descriptor*> messages; + messages.reserve(file_->message_type_count()); + for (int i = 0; i < file_->message_type_count(); ++i) { + messages.push_back(file_->message_type(i)); + } + std::sort(messages.begin(), messages.end(), SortByName<Descriptor>()); + + for (const auto& entry : messages) { + PrintMessage(*entry, false); + } +} + +void PyiGenerator::PrintServices() const { + std::vector<const ServiceDescriptor*> services; + services.reserve(file_->service_count()); + for (int i = 0; i < file_->service_count(); ++i) { + services.push_back(file_->service(i)); + } + std::sort(services.begin(), services.end(), SortByName<ServiceDescriptor>()); + + // Prints $Service$ and $Service$_Stub classes + for (const auto& entry : services) { + printer_->Print("\n"); + printer_->Print( + "class $service_name$(_service.service): ...\n\n" + "class $service_name$_Stub($service_name$): ...\n", + "service_name", entry->name()); + } +} + +bool PyiGenerator::Generate(const FileDescriptor* file, + const TProtoStringType& parameter, + GeneratorContext* context, + TProtoStringType* error) const { + MutexLock lock(&mutex_); + // Calculate file name. + file_ = file; + // proto_to_pyi.py may set the output file name directly. To replace + // proto_to_pyi.py in google3, protoc also accept --pyi_out to set + // the output file name. + TProtoStringType filename = + parameter.empty() ? GetFileName(file, ".pyi") : parameter; + + std::unique_ptr<io::ZeroCopyOutputStream> output(context->Open(filename)); + GOOGLE_CHECK(output.get()); + io::Printer printer(output.get(), '$'); + printer_ = &printer; + + // item map will store "DESCRIPTOR", top level extensions, top level enum + // values. The items will be sorted and printed later. + std::map<TProtoStringType, TProtoStringType> item_map; + + // Adds "DESCRIPTOR" into item_map. + item_map["DESCRIPTOR"] = "_descriptor.FileDescriptor"; + PrintImports(&item_map); + // Adds top level enum values to item_map. + for (int i = 0; i < file_->enum_type_count(); ++i) { + AddEnumValue(*file_->enum_type(i), &item_map); + } + // Adds top level extensions to item_map. + AddExtensions(*file_, &item_map); + // Prints item map + PrintItemMap(item_map); + + PrintMessages(); + PrintTopLevelEnums(); + if (HasGenericServices(file)) { + PrintServices(); + } + return true; +} + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google diff --git a/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.h b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.h new file mode 100644 index 00000000000..d7f5437e491 --- /dev/null +++ b/contrib/libs/protoc/src/google/protobuf/compiler/python/python_pyi_generator.h @@ -0,0 +1,104 @@ +// Protocol Buffers - Google's data interchange format +// Copyright 2008 Google Inc. All rights reserved. +// https://developers.google.com/protocol-buffers/ +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are +// met: +// +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above +// copyright notice, this list of conditions and the following disclaimer +// in the documentation and/or other materials provided with the +// distribution. +// * Neither the name of Google Inc. nor the names of its +// contributors may be used to endorse or promote products derived from +// this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// Author: [email protected] (Jie Luo) +// +// Generates Python stub (.pyi) for a given .proto file. + +#ifndef GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__ +#define GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__ + +#include <map> +#include <string> + +#include <google/protobuf/compiler/code_generator.h> +#include <google/protobuf/stubs/mutex.h> + +// Must be included last. +#include <google/protobuf/port_def.inc> + +namespace google { +namespace protobuf { +class Descriptor; +class EnumDescriptor; +class FieldDescriptor; +class MethodDescriptor; +class ServiceDescriptor; + +namespace io { +class Printer; +} + +namespace compiler { +namespace python { + +class PROTOC_EXPORT PyiGenerator : public google::protobuf::compiler::CodeGenerator { + public: + PyiGenerator(); + ~PyiGenerator() override; + + // CodeGenerator methods. + bool Generate(const FileDescriptor* file, const TProtoStringType& parameter, + GeneratorContext* generator_context, + TProtoStringType* error) const override; + + private: + void PrintImports(std::map<TProtoStringType, TProtoStringType>* item_map) const; + void PrintEnum(const EnumDescriptor& enum_descriptor) const; + void AddEnumValue(const EnumDescriptor& enum_descriptor, + std::map<TProtoStringType, TProtoStringType>* item_map) const; + void PrintTopLevelEnums() const; + template <typename DescriptorT> + void AddExtensions(const DescriptorT& descriptor, + std::map<TProtoStringType, TProtoStringType>* item_map) const; + void PrintMessages() const; + void PrintMessage(const Descriptor& message_descriptor, bool is_nested) const; + void PrintServices() const; + void PrintItemMap(const std::map<TProtoStringType, TProtoStringType>& item_map) const; + TProtoStringType GetFieldType(const FieldDescriptor& field_des) const; + template <typename DescriptorT> + TProtoStringType ModuleLevelName(const DescriptorT& descriptor) const; + + // Very coarse-grained lock to ensure that Generate() is reentrant. + // Guards file_ and printer_. + mutable Mutex mutex_; + mutable const FileDescriptor* file_; // Set in Generate(). Under mutex_. + mutable io::Printer* printer_; // Set in Generate(). Under mutex_. + GOOGLE_DISALLOW_EVIL_CONSTRUCTORS(PyiGenerator); +}; + +} // namespace python +} // namespace compiler +} // namespace protobuf +} // namespace google + +#include <google/protobuf/port_undef.inc> + +#endif // GOOGLE_PROTOBUF_COMPILER_PYTHON_PYI_GENERATOR_H__ |