aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/google/protobuf/compiler/python/python_generator.cc
diff options
context:
space:
mode:
authorGravatar Feng Xiao <xfxyjwf@gmail.com>2016-07-13 13:47:51 -0700
committerGravatar Feng Xiao <xfxyjwf@gmail.com>2016-07-13 13:48:40 -0700
commit9086d9643903c608ab015b0b7d903547a4e7b6f3 (patch)
treeb47053ab6f6bde20b55c4fff4019c68a7c45545c /src/google/protobuf/compiler/python/python_generator.cc
parent70c1ac756d3cd8fa04725f82f0ad1a30404c3bb3 (diff)
Integrate from internal code base.
Diffstat (limited to 'src/google/protobuf/compiler/python/python_generator.cc')
-rw-r--r--src/google/protobuf/compiler/python/python_generator.cc60
1 files changed, 44 insertions, 16 deletions
diff --git a/src/google/protobuf/compiler/python/python_generator.cc b/src/google/protobuf/compiler/python/python_generator.cc
index cc54a8ab..d5468a0c 100644
--- a/src/google/protobuf/compiler/python/python_generator.cc
+++ b/src/google/protobuf/compiler/python/python_generator.cc
@@ -44,6 +44,7 @@
// performance-minded Python code leverage the fast C++ implementation
// directly.
+#include <algorithm>
#include <google/protobuf/stubs/hash.h>
#include <limits>
#include <map>
@@ -107,20 +108,25 @@ string ModuleAlias(const string& filename) {
return module_name;
}
-
-// Returns an import statement of form "from X.Y.Z import T" for the given
-// .proto filename.
-string ModuleImportStatement(const string& filename) {
- string module_name = ModuleName(filename);
- int last_dot_pos = module_name.rfind('.');
- if (last_dot_pos == string::npos) {
- // NOTE(petya): this is not tested as it would require a protocol buffer
- // outside of any package, and I don't think that is easily achievable.
- return "import " + module_name;
- } else {
- return "from " + module_name.substr(0, last_dot_pos) + " import " +
- module_name.substr(last_dot_pos + 1);
+// Keywords reserved by the Python language.
+const char* const kKeywords[] = {
+ "False", "None", "True", "and", "as", "assert", "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",
+};
+const char* const* kKeywordsEnd =
+ kKeywords + (sizeof(kKeywords) / sizeof(kKeywords[0]));
+
+bool ContainsPythonKeyword(const string& module_name) {
+ vector<string> tokens = Split(module_name, ".");
+ for (int i = 0; i < tokens.size(); ++i) {
+ if (std::find(kKeywords, kKeywordsEnd, tokens[i]) != kKeywordsEnd) {
+ return true;
+ }
}
+ return false;
}
@@ -359,10 +365,32 @@ bool Generator::Generate(const FileDescriptor* file,
void Generator::PrintImports() const {
for (int i = 0; i < file_->dependency_count(); ++i) {
const string& filename = file_->dependency(i)->name();
- string import_statement = ModuleImportStatement(filename);
+
+ string module_name = ModuleName(filename);
string module_alias = ModuleAlias(filename);
- printer_->Print("$statement$ as $alias$\n", "statement",
- import_statement, "alias", module_alias);
+ if (ContainsPythonKeyword(module_name)) {
+ // If the module path contains a Python keyword, we have to quote the
+ // module name and import it using importlib. Otherwise the usual kind of
+ // import statement would result in a syntax error from the presence of
+ // the keyword.
+ printer_->Print("import importlib\n");
+ printer_->Print("$alias$ = importlib.import_module('$name$')\n", "alias",
+ module_alias, "name", module_name);
+ } else {
+ int last_dot_pos = module_name.rfind('.');
+ string import_statement;
+ if (last_dot_pos == string::npos) {
+ // NOTE(petya): this is not tested as it would require a protocol buffer
+ // outside of any package, and I don't think that is easily achievable.
+ import_statement = "import " + module_name;
+ } else {
+ import_statement = "from " + module_name.substr(0, last_dot_pos) +
+ " import " + module_name.substr(last_dot_pos + 1);
+ }
+ printer_->Print("$statement$ as $alias$\n", "statement", import_statement,
+ "alias", module_alias);
+ }
+
CopyPublicDependenciesAliases(module_alias, file_->dependency(i));
}
printer_->Print("\n");