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