[Python] Fix various codegen problems (#8292)
* [Python] Fix various codegen problems.
This includes:
- escaping keywords happens **after** converting the case:
- currently, `table ClassT` generate `class = Class()` which is invalid Python;
- imports in `one_file` mode use the filename rather than the type name when resolving module names;
- use `filename_suffix` instead of the hardcoded `_generated` one;
- generate empty files if no structs or enums are available. This makes the set of output files more predictable for Bazel.
* [Python] Fix various codegen problems.
This includes:
- escaping keywords happens **after** converting the case:
- currently, `table ClassT` generate `class = Class()` which is invalid Python;
- imports in `one_file` mode use the filename rather than the type name when resolving module names;
- use `filename_suffix` instead of the hardcoded `_generated` one;
- generate empty files if no structs or enums are available. This makes the set of output files more predictable for Bazel.
diff --git a/src/idl_gen_python.cpp b/src/idl_gen_python.cpp
index 9e16275..a6bc0f5 100644
--- a/src/idl_gen_python.cpp
+++ b/src/idl_gen_python.cpp
@@ -18,7 +18,9 @@
#include "idl_gen_python.h"
+#include <algorithm>
#include <cctype>
+#include <cstdio>
#include <set>
#include <string>
#include <unordered_set>
@@ -56,7 +58,7 @@
/*variable=*/Case::kLowerCamel,
/*variants=*/Case::kKeep,
/*enum_variant_seperator=*/".",
- /*escape_keywords=*/Namer::Config::Escape::BeforeConvertingCase,
+ /*escape_keywords=*/Namer::Config::Escape::AfterConvertingCase,
/*namespaces=*/Case::kKeep, // Packages in python.
/*namespace_seperator=*/".",
/*object_prefix=*/"",
@@ -424,16 +426,29 @@
code += Indent + Indent + "return None\n\n";
}
+ template <typename T>
+ std::string ModuleFor(const T *def) const {
+ if (!parser_.opts.one_file) {
+ return namer_.NamespacedType(*def);
+ }
+
+ std::string filename =
+ StripExtension(def->file) + parser_.opts.filename_suffix;
+ if (parser_.file_being_parsed_ == def->file) {
+ return "." + StripPath(filename); // make it a "local" import
+ }
+
+ std::string module = parser_.opts.include_prefix + filename;
+ std::replace(module.begin(), module.end(), '/', '.');
+ return module;
+ }
+
// Generate the package reference when importing a struct or enum from its
// module.
std::string GenPackageReference(const Type &type) const {
- if (type.struct_def) {
- return namer_.NamespacedType(*type.struct_def);
- } else if (type.enum_def) {
- return namer_.NamespacedType(*type.enum_def);
- } else {
- return "." + GenTypeGet(type);
- }
+ if (type.struct_def) return ModuleFor(type.struct_def);
+ if (type.enum_def) return ModuleFor(type.enum_def);
+ return "." + GenTypeGet(type);
}
// Get the value of a vector's struct member.
@@ -2021,7 +2036,7 @@
if (!generateStructs(&one_file_code, one_file_imports)) return false;
if (parser_.opts.one_file) {
- const std::string mod = file_name_ + "_generated";
+ const std::string mod = file_name_ + parser_.opts.filename_suffix;
// Legacy file format uses keep casing.
return SaveType(mod + ".py", *parser_.current_namespace_, one_file_code,
@@ -2122,11 +2137,13 @@
bool SaveType(const std::string &defname, const Namespace &ns,
const std::string &classcode, const ImportMap &imports,
const std::string &mod, bool needs_imports) const {
- if (!classcode.length()) return true;
-
std::string code = "";
- BeginFile(LastNamespacePart(ns), needs_imports, &code, mod, imports);
- code += classcode;
+ if (classcode.empty()) {
+ BeginFile(LastNamespacePart(ns), false, &code, "", {});
+ } else {
+ BeginFile(LastNamespacePart(ns), needs_imports, &code, mod, imports);
+ code += classcode;
+ }
const std::string directories =
parser_.opts.one_file ? path_ : namer_.Directories(ns.components);
diff --git a/tests/FromInclude.py b/tests/FromInclude.py
new file mode 100644
index 0000000..0476017
--- /dev/null
+++ b/tests/FromInclude.py
@@ -0,0 +1,4 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: OtherNameSpace
+
diff --git a/tests/MyGame/OtherNameSpace/FromInclude.py b/tests/MyGame/OtherNameSpace/FromInclude.py
new file mode 100644
index 0000000..0476017
--- /dev/null
+++ b/tests/MyGame/OtherNameSpace/FromInclude.py
@@ -0,0 +1,4 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: OtherNameSpace
+
diff --git a/tests/MyGame/OtherNameSpace/TableB.py b/tests/MyGame/OtherNameSpace/TableB.py
new file mode 100644
index 0000000..0476017
--- /dev/null
+++ b/tests/MyGame/OtherNameSpace/TableB.py
@@ -0,0 +1,4 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: OtherNameSpace
+
diff --git a/tests/MyGame/OtherNameSpace/Unused.py b/tests/MyGame/OtherNameSpace/Unused.py
new file mode 100644
index 0000000..0476017
--- /dev/null
+++ b/tests/MyGame/OtherNameSpace/Unused.py
@@ -0,0 +1,4 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace: OtherNameSpace
+
diff --git a/tests/MyGame/OtherNameSpace/__init__.py b/tests/MyGame/OtherNameSpace/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/MyGame/OtherNameSpace/__init__.py
diff --git a/tests/PythonTest.sh b/tests/PythonTest.sh
index 84e8201..e7199b8 100755
--- a/tests/PythonTest.sh
+++ b/tests/PythonTest.sh
@@ -24,9 +24,9 @@
# Emit Python code for the example schema in the test dir:
${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_test.fbs --gen-object-api
${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_test.fbs --gen-object-api --gen-onefile
-${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_extra.fbs --gen-object-api
-${test_dir}/../flatc -p -o ${gen_code_path} -I include_test arrays_test.fbs --gen-object-api
-${test_dir}/../flatc -p -o ${gen_code_path} -I include_test nested_union_test.fbs --gen-object-api
+${test_dir}/../flatc -p -o ${gen_code_path} -I include_test monster_extra.fbs --gen-object-api --python-typing --gen-compare
+${test_dir}/../flatc -p -o ${gen_code_path} -I include_test arrays_test.fbs --gen-object-api --python-typing
+${test_dir}/../flatc -p -o ${gen_code_path} -I include_test nested_union_test.fbs --gen-object-api --python-typing
# Syntax: run_tests <interpreter> <benchmark vtable dedupes>
# <benchmark read count> <benchmark build count>
diff --git a/tests/TableA.py b/tests/TableA.py
new file mode 100644
index 0000000..ca9b83e
--- /dev/null
+++ b/tests/TableA.py
@@ -0,0 +1,4 @@
+# automatically generated by the FlatBuffers compiler, do not modify
+
+# namespace:
+
diff --git a/tests/__init__.py b/tests/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/__init__.py