• 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/helpers.h"
9 
10 #include <algorithm>
11 #include <string>
12 #include <vector>
13 
14 #include "absl/log/absl_check.h"
15 #include "absl/strings/escaping.h"
16 #include "absl/strings/match.h"
17 #include "absl/strings/str_replace.h"
18 #include "absl/strings/str_split.h"
19 #include "absl/strings/string_view.h"
20 #include "absl/strings/strip.h"
21 #include "google/protobuf/compiler/code_generator.h"
22 #include "google/protobuf/descriptor.h"
23 #include "google/protobuf/descriptor.pb.h"
24 
25 namespace google {
26 namespace protobuf {
27 namespace compiler {
28 namespace python {
29 
30 // Returns the Python module name expected for a given .proto filename.
ModuleName(absl::string_view filename)31 std::string ModuleName(absl::string_view filename) {
32   std::string basename = StripProto(filename);
33   absl::StrReplaceAll({{"-", "_"}, {"/", "."}}, &basename);
34   return absl::StrCat(basename, "_pb2");
35 }
36 
StrippedModuleName(absl::string_view filename)37 std::string StrippedModuleName(absl::string_view filename) {
38   std::string module_name = ModuleName(filename);
39   return module_name;
40 }
41 
42 // Keywords reserved by the Python language.
43 const char* const kKeywords[] = {
44     "False",  "None",     "True",  "and",    "as",       "assert",
45     "async",  "await",    "break", "class",  "continue", "def",
46     "del",    "elif",     "else",  "except", "finally",  "for",
47     "from",   "global",   "if",    "import", "in",       "is",
48     "lambda", "nonlocal", "not",   "or",     "pass",     "raise",
49     "return", "try",      "while", "with",   "yield",
50 };
51 const char* const* kKeywordsEnd =
52     kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
53 
ContainsPythonKeyword(absl::string_view module_name)54 bool ContainsPythonKeyword(absl::string_view module_name) {
55   std::vector<absl::string_view> tokens = absl::StrSplit(module_name, '.');
56   for (int i = 0; i < static_cast<int>(tokens.size()); ++i) {
57     if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
58       return true;
59     }
60   }
61   return false;
62 }
63 
IsPythonKeyword(absl::string_view name)64 bool IsPythonKeyword(absl::string_view name) {
65   return (std::find(kKeywords, kKeywordsEnd, name) != kKeywordsEnd);
66 }
67 
ResolveKeyword(absl::string_view name)68 std::string ResolveKeyword(absl::string_view name) {
69   if (IsPythonKeyword(name)) {
70     return absl::StrCat("globals()['", name, "']");
71   }
72   return std::string(name);
73 }
74 
GetFileName(const FileDescriptor * file_des,absl::string_view suffix)75 std::string GetFileName(const FileDescriptor* file_des,
76                         absl::string_view suffix) {
77   std::string module_name = ModuleName(file_des->name());
78   std::string filename = module_name;
79   absl::StrReplaceAll({{".", "/"}}, &filename);
80   absl::StrAppend(&filename, suffix);
81   return filename;
82 }
83 
HasGenericServices(const FileDescriptor * file)84 bool HasGenericServices(const FileDescriptor* file) {
85   return file->service_count() > 0 && file->options().py_generic_services();
86 }
87 
GeneratedCodeToBase64(const GeneratedCodeInfo & annotations)88 std::string GeneratedCodeToBase64(const GeneratedCodeInfo& annotations) {
89   std::string result;
90   absl::Base64Escape(annotations.SerializeAsString(), &result);
91   return result;
92 }
93 
94 template <typename DescriptorT>
NamePrefixedWithNestedTypes(const DescriptorT & descriptor,absl::string_view separator)95 std::string NamePrefixedWithNestedTypes(const DescriptorT& descriptor,
96                                         absl::string_view separator) {
97   std::string name = std::string(descriptor.name());
98   const Descriptor* parent = descriptor.containing_type();
99   if (parent != nullptr) {
100     std::string prefix = NamePrefixedWithNestedTypes(*parent, separator);
101     if (separator == "." && IsPythonKeyword(name)) {
102       return absl::StrCat("getattr(", prefix, ", '", name, "')");
103     } else {
104       return absl::StrCat(prefix, separator, name);
105     }
106   }
107   if (separator == ".") {
108     name = ResolveKeyword(name);
109   }
110   return name;
111 }
112 
113 template std::string NamePrefixedWithNestedTypes<Descriptor>(
114     const Descriptor& descriptor, absl::string_view separator);
115 template std::string NamePrefixedWithNestedTypes<EnumDescriptor>(
116     const EnumDescriptor& descriptor, absl::string_view separator);
117 
118 }  // namespace python
119 }  // namespace compiler
120 }  // namespace protobuf
121 }  // namespace google
122