• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google Inc. All rights reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 // independent from idl_parser, since this code is not needed for most clients
18 
19 #include <cctype>
20 #include <set>
21 #include <string>
22 #include <unordered_set>
23 #include <vector>
24 
25 #include "flatbuffers/code_generators.h"
26 #include "flatbuffers/flatbuffers.h"
27 #include "flatbuffers/idl.h"
28 #include "flatbuffers/util.h"
29 
30 namespace flatbuffers {
31 namespace python {
32 
33 // Hardcode spaces per indentation.
34 const CommentConfig def_comment = { nullptr, "#", nullptr };
35 const std::string Indent = "    ";
36 
37 class PythonGenerator : public BaseGenerator {
38  public:
PythonGenerator(const Parser & parser,const std::string & path,const std::string & file_name)39   PythonGenerator(const Parser &parser, const std::string &path,
40                   const std::string &file_name)
41       : BaseGenerator(parser, path, file_name, "" /* not used */,
42                       "" /* not used */, "py"),
43         float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
44     static const char *const keywords[] = {
45       "False",   "None",     "True",     "and",    "as",   "assert", "break",
46       "class",   "continue", "def",      "del",    "elif", "else",   "except",
47       "finally", "for",      "from",     "global", "if",   "import", "in",
48       "is",      "lambda",   "nonlocal", "not",    "or",   "pass",   "raise",
49       "return",  "try",      "while",    "with",   "yield"
50     };
51     keywords_.insert(std::begin(keywords), std::end(keywords));
52   }
53 
54   // Most field accessors need to retrieve and test the field offset first,
55   // this is the prefix code for that.
OffsetPrefix(const FieldDef & field)56   std::string OffsetPrefix(const FieldDef &field) {
57     return "\n" + Indent + Indent +
58            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
59            "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
60            Indent + Indent + "if o != 0:\n";
61   }
62 
63   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr)64   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
65     auto &code = *code_ptr;
66     code += "class " + NormalizedName(struct_def) + "(object):\n";
67     code += Indent + "__slots__ = ['_tab']";
68     code += "\n\n";
69   }
70 
71   // Begin enum code with a class declaration.
BeginEnum(const std::string & class_name,std::string * code_ptr)72   void BeginEnum(const std::string &class_name, std::string *code_ptr) {
73     auto &code = *code_ptr;
74     code += "class " + class_name + "(object):\n";
75   }
76 
EscapeKeyword(const std::string & name) const77   std::string EscapeKeyword(const std::string &name) const {
78     return keywords_.find(name) == keywords_.end() ? name : name + "_";
79   }
80 
NormalizedName(const Definition & definition) const81   std::string NormalizedName(const Definition &definition) const {
82     return EscapeKeyword(definition.name);
83   }
84 
NormalizedName(const EnumVal & ev) const85   std::string NormalizedName(const EnumVal &ev) const {
86     return EscapeKeyword(ev.name);
87   }
88 
89   // Converts the name of a definition into upper Camel format.
MakeUpperCamel(const Definition & definition) const90   std::string MakeUpperCamel(const Definition &definition) const {
91     return MakeCamel(NormalizedName(definition), true);
92   }
93 
94   // Converts the name of a definition into lower Camel format.
MakeLowerCamel(const Definition & definition) const95   std::string MakeLowerCamel(const Definition &definition) const {
96     auto name = MakeCamel(NormalizedName(definition), false);
97     name[0] = char(tolower(name[0]));
98     return name;
99   }
100 
101   // Starts a new line and then indents.
GenIndents(int num)102   std::string GenIndents(int num) {
103     return "\n" + std::string(num * Indent.length(), ' ');
104   }
105 
106   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)107   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
108                   std::string *code_ptr) {
109     auto &code = *code_ptr;
110     code += Indent;
111     code += NormalizedName(ev);
112     code += " = ";
113     code += enum_def.ToString(ev) + "\n";
114   }
115 
116   // End enum code.
EndEnum(std::string * code_ptr)117   void EndEnum(std::string *code_ptr) {
118     auto &code = *code_ptr;
119     code += "\n";
120   }
121 
122   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr)123   void NewRootTypeFromBuffer(const StructDef &struct_def,
124                              std::string *code_ptr) {
125     auto &code = *code_ptr;
126 
127     code += Indent + "@classmethod\n";
128     code += Indent + "def GetRootAs";
129     code += NormalizedName(struct_def);
130     code += "(cls, buf, offset):";
131     code += "\n";
132     code += Indent + Indent;
133     code += "n = flatbuffers.encode.Get";
134     code += "(flatbuffers.packer.uoffset, buf, offset)\n";
135     code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
136     code += Indent + Indent + "x.Init(buf, n + offset)\n";
137     code += Indent + Indent + "return x\n";
138     code += "\n";
139   }
140 
141   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr)142   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
143     auto &code = *code_ptr;
144 
145     GenReceiver(struct_def, code_ptr);
146     code += "Init(self, buf, pos):\n";
147     code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
148     code += "\n";
149   }
150 
151   // Get the length of a vector.
GetVectorLen(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)152   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
153                     std::string *code_ptr) {
154     auto &code = *code_ptr;
155 
156     GenReceiver(struct_def, code_ptr);
157     code += MakeCamel(NormalizedName(field)) + "Length(self";
158     code += "):" + OffsetPrefix(field);
159     code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
160     code += Indent + Indent + "return 0\n\n";
161   }
162 
163   // Determines whether a vector is none or not.
GetVectorIsNone(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)164   void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
165                        std::string *code_ptr) {
166     auto &code = *code_ptr;
167 
168     GenReceiver(struct_def, code_ptr);
169     code += MakeCamel(NormalizedName(field)) + "IsNone(self";
170     code += "):";
171     code += GenIndents(2) +
172             "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
173             "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
174     code += GenIndents(2) + "return o == 0";
175     code += "\n\n";
176   }
177 
178   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)179   void GetScalarFieldOfStruct(const StructDef &struct_def,
180                               const FieldDef &field, std::string *code_ptr) {
181     auto &code = *code_ptr;
182     std::string getter = GenGetter(field.value.type);
183     GenReceiver(struct_def, code_ptr);
184     code += MakeCamel(NormalizedName(field));
185     code += "(self): return " + getter;
186     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
187     code += NumToString(field.value.offset) + "))\n";
188   }
189 
190   // Get the value of a table's scalar.
GetScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)191   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
192                              std::string *code_ptr) {
193     auto &code = *code_ptr;
194     std::string getter = GenGetter(field.value.type);
195     GenReceiver(struct_def, code_ptr);
196     code += MakeCamel(NormalizedName(field));
197     code += "(self):";
198     code += OffsetPrefix(field);
199     getter += "o + self._tab.Pos)";
200     auto is_bool = IsBool(field.value.type.base_type);
201     if (is_bool) { getter = "bool(" + getter + ")"; }
202     code += Indent + Indent + Indent + "return " + getter + "\n";
203     std::string default_value;
204     if (is_bool) {
205       default_value = field.value.constant == "0" ? "False" : "True";
206     } else {
207       default_value = IsFloat(field.value.type.base_type)
208                           ? float_const_gen_.GenFloatConstant(field)
209                           : field.value.constant;
210     }
211     code += Indent + Indent + "return " + default_value + "\n\n";
212   }
213 
214   // Get a struct by initializing an existing struct.
215   // Specific to Struct.
GetStructFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)216   void GetStructFieldOfStruct(const StructDef &struct_def,
217                               const FieldDef &field, std::string *code_ptr) {
218     auto &code = *code_ptr;
219     GenReceiver(struct_def, code_ptr);
220     code += MakeCamel(NormalizedName(field));
221     code += "(self, obj):\n";
222     code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
223     code += NumToString(field.value.offset) + ")";
224     code += "\n" + Indent + Indent + "return obj\n\n";
225   }
226 
227   // Get the value of a fixed size array.
GetArrayOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)228   void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
229                         std::string *code_ptr) {
230     auto &code = *code_ptr;
231     const auto vec_type = field.value.type.VectorType();
232     GenReceiver(struct_def, code_ptr);
233     code += MakeCamel(NormalizedName(field));
234     if (IsStruct(vec_type)) {
235       code += "(self, obj, i):\n";
236       code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
237       code += NumToString(field.value.offset) + " + i * ";
238       code += NumToString(InlineSize(vec_type));
239       code += ")\n" + Indent + Indent + "return obj\n\n";
240     } else {
241       auto getter = GenGetter(vec_type);
242       code += "(self): return [" + getter;
243       code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
244       code += NumToString(field.value.offset) + " + i * ";
245       code += NumToString(InlineSize(vec_type));
246       code += ")) for i in range(";
247       code += NumToString(field.value.type.fixed_length) + ")]\n";
248     }
249   }
250 
251   // Get a struct by initializing an existing struct.
252   // Specific to Table.
GetStructFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)253   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
254                              std::string *code_ptr) {
255     auto &code = *code_ptr;
256     GenReceiver(struct_def, code_ptr);
257     code += MakeCamel(NormalizedName(field));
258     code += "(self):";
259     code += OffsetPrefix(field);
260     if (field.value.type.struct_def->fixed) {
261       code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
262     } else {
263       code += Indent + Indent + Indent;
264       code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
265     }
266     if (parser_.opts.include_dependence_headers) {
267       code += Indent + Indent + Indent;
268       code += "from " + GenPackageReference(field.value.type) + " import " +
269               TypeName(field) + "\n";
270     }
271     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
272     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
273     code += Indent + Indent + Indent + "return obj\n";
274     code += Indent + Indent + "return None\n\n";
275   }
276 
277   // Get the value of a string.
GetStringField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)278   void GetStringField(const StructDef &struct_def, const FieldDef &field,
279                       std::string *code_ptr) {
280     auto &code = *code_ptr;
281     GenReceiver(struct_def, code_ptr);
282     code += MakeCamel(NormalizedName(field));
283     code += "(self):";
284     code += OffsetPrefix(field);
285     code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
286     code += "o + self._tab.Pos)\n";
287     code += Indent + Indent + "return None\n\n";
288   }
289 
290   // Get the value of a union from an object.
GetUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)291   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
292                      std::string *code_ptr) {
293     auto &code = *code_ptr;
294     GenReceiver(struct_def, code_ptr);
295     code += MakeCamel(NormalizedName(field)) + "(self):";
296     code += OffsetPrefix(field);
297 
298     // TODO(rw): this works and is not the good way to it:
299     bool is_native_table = TypeName(field) == "*flatbuffers.Table";
300     if (is_native_table) {
301       code +=
302           Indent + Indent + Indent + "from flatbuffers.table import Table\n";
303     } else if (parser_.opts.include_dependence_headers) {
304       code += Indent + Indent + Indent;
305       code += "from " + GenPackageReference(field.value.type) + " import " +
306               TypeName(field) + "\n";
307     }
308     code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
309     code += Indent + Indent + Indent + GenGetter(field.value.type);
310     code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
311     code += Indent + Indent + "return None\n\n";
312   }
313 
314   // Generate the package reference when importing a struct or enum from its
315   // module.
GenPackageReference(const Type & type)316   std::string GenPackageReference(const Type &type) {
317     Namespace *namespaces;
318     if (type.struct_def) {
319       namespaces = type.struct_def->defined_namespace;
320     } else if (type.enum_def) {
321       namespaces = type.enum_def->defined_namespace;
322     } else {
323       return "." + GenTypeGet(type);
324     }
325 
326     return namespaces->GetFullyQualifiedName(GenTypeGet(type));
327   }
328 
329   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)330   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
331                                  const FieldDef &field, std::string *code_ptr) {
332     auto &code = *code_ptr;
333     auto vectortype = field.value.type.VectorType();
334 
335     GenReceiver(struct_def, code_ptr);
336     code += MakeCamel(NormalizedName(field));
337     code += "(self, j):" + OffsetPrefix(field);
338     code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
339     code += Indent + Indent + Indent;
340     code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
341     code += NumToString(InlineSize(vectortype)) + "\n";
342     if (!(vectortype.struct_def->fixed)) {
343       code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
344     }
345     if (parser_.opts.include_dependence_headers) {
346       code += Indent + Indent + Indent;
347       code += "from " + GenPackageReference(field.value.type) + " import " +
348               TypeName(field) + "\n";
349     }
350     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
351     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
352     code += Indent + Indent + Indent + "return obj\n";
353     code += Indent + Indent + "return None\n\n";
354   }
355 
356   // Get the value of a vector's non-struct member. Uses a named return
357   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)358   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
359                                     const FieldDef &field,
360                                     std::string *code_ptr) {
361     auto &code = *code_ptr;
362     auto vectortype = field.value.type.VectorType();
363 
364     GenReceiver(struct_def, code_ptr);
365     code += MakeCamel(NormalizedName(field));
366     code += "(self, j):";
367     code += OffsetPrefix(field);
368     code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
369     code += Indent + Indent + Indent;
370     code += "return " + GenGetter(field.value.type);
371     code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
372     code += NumToString(InlineSize(vectortype)) + "))\n";
373     if (vectortype.base_type == BASE_TYPE_STRING) {
374       code += Indent + Indent + "return \"\"\n";
375     } else {
376       code += Indent + Indent + "return 0\n";
377     }
378     code += "\n";
379   }
380 
381   // Returns a non-struct vector as a numpy array. Much faster
382   // than iterating over the vector element by element.
GetVectorOfNonStructAsNumpy(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)383   void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
384                                    const FieldDef &field,
385                                    std::string *code_ptr) {
386     auto &code = *code_ptr;
387     auto vectortype = field.value.type.VectorType();
388 
389     // Currently, we only support accessing as numpy array if
390     // the vector type is a scalar.
391     if (!(IsScalar(vectortype.base_type))) { return; }
392 
393     GenReceiver(struct_def, code_ptr);
394     code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
395     code += OffsetPrefix(field);
396 
397     code += Indent + Indent + Indent;
398     code += "return ";
399     code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
400     code += MakeCamel(GenTypeGet(field.value.type));
401     code += "Flags, o)\n";
402 
403     if (vectortype.base_type == BASE_TYPE_STRING) {
404       code += Indent + Indent + "return \"\"\n";
405     } else {
406       code += Indent + Indent + "return 0\n";
407     }
408     code += "\n";
409   }
410 
411   // Begin the creator function signature.
BeginBuilderArgs(const StructDef & struct_def,std::string * code_ptr)412   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
413     auto &code = *code_ptr;
414 
415     code += "\n";
416     code += "def Create" + NormalizedName(struct_def);
417     code += "(builder";
418   }
419 
420   // Recursively generate arguments for a constructor, to deal with nested
421   // structs.
StructBuilderArgs(const StructDef & struct_def,const std::string nameprefix,const std::string namesuffix,bool has_field_name,const std::string fieldname_suffix,std::string * code_ptr)422   void StructBuilderArgs(const StructDef &struct_def,
423                          const std::string nameprefix,
424                          const std::string namesuffix, bool has_field_name,
425                          const std::string fieldname_suffix,
426                          std::string *code_ptr) {
427     for (auto it = struct_def.fields.vec.begin();
428          it != struct_def.fields.vec.end(); ++it) {
429       auto &field = **it;
430       const auto &field_type = field.value.type;
431       const auto &type =
432           IsArray(field_type) ? field_type.VectorType() : field_type;
433       if (IsStruct(type)) {
434         // Generate arguments for a struct inside a struct. To ensure names
435         // don't clash, and to make it obvious these arguments are constructing
436         // a nested struct, prefix the name with the field name.
437         auto subprefix = nameprefix;
438         if (has_field_name) {
439           subprefix += NormalizedName(field) + fieldname_suffix;
440         }
441         StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
442                           has_field_name, fieldname_suffix, code_ptr);
443       } else {
444         auto &code = *code_ptr;
445         code += std::string(", ") + nameprefix;
446         if (has_field_name) { code += MakeCamel(NormalizedName(field), false); }
447         code += namesuffix;
448       }
449     }
450   }
451 
452   // End the creator function signature.
EndBuilderArgs(std::string * code_ptr)453   void EndBuilderArgs(std::string *code_ptr) {
454     auto &code = *code_ptr;
455     code += "):\n";
456   }
457 
458   // Recursively generate struct construction statements and instert manual
459   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr,size_t index=0,bool in_array=false)460   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
461                          std::string *code_ptr, size_t index = 0,
462                          bool in_array = false) {
463     auto &code = *code_ptr;
464     std::string indent(index * 4, ' ');
465     code +=
466         indent + "    builder.Prep(" + NumToString(struct_def.minalign) + ", ";
467     code += NumToString(struct_def.bytesize) + ")\n";
468     for (auto it = struct_def.fields.vec.rbegin();
469          it != struct_def.fields.vec.rend(); ++it) {
470       auto &field = **it;
471       const auto &field_type = field.value.type;
472       const auto &type =
473           IsArray(field_type) ? field_type.VectorType() : field_type;
474       if (field.padding)
475         code +=
476             indent + "    builder.Pad(" + NumToString(field.padding) + ")\n";
477       if (IsStruct(field_type)) {
478         StructBuilderBody(*field_type.struct_def,
479                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
480                           code_ptr, index, in_array);
481       } else {
482         const auto index_var = "_idx" + NumToString(index);
483         if (IsArray(field_type)) {
484           code += indent + "    for " + index_var + " in range(";
485           code += NumToString(field_type.fixed_length);
486           code += " , 0, -1):\n";
487           in_array = true;
488         }
489         if (IsStruct(type)) {
490           StructBuilderBody(
491               *field_type.struct_def,
492               (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
493               index + 1, in_array);
494         } else {
495           code += IsArray(field_type) ? "    " : "";
496           code += indent + "    builder.Prepend" + GenMethod(field) + "(";
497           code += nameprefix + MakeCamel(NormalizedName(field), false);
498           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
499           for (size_t i = 0; in_array && i < array_cnt; i++) {
500             code += "[_idx" + NumToString(i) + "-1]";
501           }
502           code += ")\n";
503         }
504       }
505     }
506   }
507 
EndBuilderBody(std::string * code_ptr)508   void EndBuilderBody(std::string *code_ptr) {
509     auto &code = *code_ptr;
510     code += "    return builder.Offset()\n";
511   }
512 
513   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr)514   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
515     auto &code = *code_ptr;
516     code += "def " + NormalizedName(struct_def) + "Start";
517     code += "(builder): ";
518     code += "builder.StartObject(";
519     code += NumToString(struct_def.fields.vec.size());
520     code += ")\n";
521   }
522 
523   // Set the value of a table's field.
BuildFieldOfTable(const StructDef & struct_def,const FieldDef & field,const size_t offset,std::string * code_ptr)524   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
525                          const size_t offset, std::string *code_ptr) {
526     auto &code = *code_ptr;
527     code += "def " + NormalizedName(struct_def) + "Add" +
528             MakeCamel(NormalizedName(field));
529     code += "(builder, ";
530     code += MakeCamel(NormalizedName(field), false);
531     code += "): ";
532     code += "builder.Prepend";
533     code += GenMethod(field) + "Slot(";
534     code += NumToString(offset) + ", ";
535     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
536       code += "flatbuffers.number_types.UOffsetTFlags.py_type";
537       code += "(";
538       code += MakeCamel(NormalizedName(field), false) + ")";
539     } else {
540       code += MakeCamel(NormalizedName(field), false);
541     }
542     code += ", ";
543     code += IsFloat(field.value.type.base_type)
544                 ? float_const_gen_.GenFloatConstant(field)
545                 : field.value.constant;
546     code += ")\n";
547   }
548 
549   // Set the value of one of the members of a table's vector.
BuildVectorOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)550   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
551                           std::string *code_ptr) {
552     auto &code = *code_ptr;
553     code += "def " + NormalizedName(struct_def) + "Start";
554     code += MakeCamel(NormalizedName(field));
555     code += "Vector(builder, numElems): return builder.StartVector(";
556     auto vector_type = field.value.type.VectorType();
557     auto alignment = InlineAlignment(vector_type);
558     auto elem_size = InlineSize(vector_type);
559     code += NumToString(elem_size);
560     code += ", numElems, " + NumToString(alignment);
561     code += ")\n";
562   }
563 
564   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr)565   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
566     auto &code = *code_ptr;
567     code += "def " + NormalizedName(struct_def) + "End";
568     code += "(builder): ";
569     code += "return builder.EndObject()\n";
570   }
571 
572   // Generate the receiver for function signatures.
GenReceiver(const StructDef & struct_def,std::string * code_ptr)573   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
574     auto &code = *code_ptr;
575     code += Indent + "# " + NormalizedName(struct_def) + "\n";
576     code += Indent + "def ";
577   }
578 
579   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)580   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
581                          std::string *code_ptr) {
582     GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
583     if (IsScalar(field.value.type.base_type)) {
584       if (struct_def.fixed) {
585         GetScalarFieldOfStruct(struct_def, field, code_ptr);
586       } else {
587         GetScalarFieldOfTable(struct_def, field, code_ptr);
588       }
589     } else if (IsArray(field.value.type)) {
590       GetArrayOfStruct(struct_def, field, code_ptr);
591     } else {
592       switch (field.value.type.base_type) {
593         case BASE_TYPE_STRUCT:
594           if (struct_def.fixed) {
595             GetStructFieldOfStruct(struct_def, field, code_ptr);
596           } else {
597             GetStructFieldOfTable(struct_def, field, code_ptr);
598           }
599           break;
600         case BASE_TYPE_STRING:
601           GetStringField(struct_def, field, code_ptr);
602           break;
603         case BASE_TYPE_VECTOR: {
604           auto vectortype = field.value.type.VectorType();
605           if (vectortype.base_type == BASE_TYPE_STRUCT) {
606             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
607           } else {
608             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
609             GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
610           }
611           break;
612         }
613         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
614         default: FLATBUFFERS_ASSERT(0);
615       }
616     }
617     if (field.value.type.base_type == BASE_TYPE_VECTOR ||
618         field.value.type.base_type == BASE_TYPE_ARRAY) {
619       GetVectorLen(struct_def, field, code_ptr);
620       GetVectorIsNone(struct_def, field, code_ptr);
621     }
622   }
623 
624   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr)625   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
626     GetStartOfTable(struct_def, code_ptr);
627 
628     for (auto it = struct_def.fields.vec.begin();
629          it != struct_def.fields.vec.end(); ++it) {
630       auto &field = **it;
631       if (field.deprecated) continue;
632 
633       auto offset = it - struct_def.fields.vec.begin();
634       BuildFieldOfTable(struct_def, field, offset, code_ptr);
635       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
636         BuildVectorOfTable(struct_def, field, code_ptr);
637       }
638     }
639 
640     GetEndOffsetOnTable(struct_def, code_ptr);
641   }
642 
643   // Generate function to check for proper file identifier
GenHasFileIdentifier(const StructDef & struct_def,std::string * code_ptr)644   void GenHasFileIdentifier(const StructDef &struct_def,
645                             std::string *code_ptr) {
646     auto &code = *code_ptr;
647     std::string escapedID;
648     // In the event any of file_identifier characters are special(NULL, \, etc),
649     // problems occur. To prevent this, convert all chars to their hex-escaped
650     // equivalent.
651     for (auto it = parser_.file_identifier_.begin();
652          it != parser_.file_identifier_.end(); ++it) {
653       escapedID += "\\x" + IntToStringHex(*it, 2);
654     }
655 
656     code += Indent + "@classmethod\n";
657     code += Indent + "def " + NormalizedName(struct_def);
658     code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
659     code += "\n";
660     code += Indent + Indent;
661     code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
662     code += escapedID;
663     code += "\", size_prefixed=size_prefixed)\n";
664     code += "\n";
665   }
666 
667   // Generates struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr)668   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
669     if (struct_def.generated) return;
670 
671     GenComment(struct_def.doc_comment, code_ptr, &def_comment);
672     BeginClass(struct_def, code_ptr);
673     if (!struct_def.fixed) {
674       // Generate a special accessor for the table that has been declared as
675       // the root type.
676       NewRootTypeFromBuffer(struct_def, code_ptr);
677       if (parser_.file_identifier_.length()) {
678         // Generate a special function to test file_identifier
679         GenHasFileIdentifier(struct_def, code_ptr);
680       }
681     }
682     // Generates the Init method that sets the field in a pre-existing
683     // accessor object. This is to allow object reuse.
684     InitializeExisting(struct_def, code_ptr);
685     for (auto it = struct_def.fields.vec.begin();
686          it != struct_def.fields.vec.end(); ++it) {
687       auto &field = **it;
688       if (field.deprecated) continue;
689 
690       GenStructAccessor(struct_def, field, code_ptr);
691     }
692 
693     if (struct_def.fixed) {
694       // creates a struct constructor function
695       GenStructBuilder(struct_def, code_ptr);
696     } else {
697       // Creates a set of functions that allow table construction.
698       GenTableBuilders(struct_def, code_ptr);
699     }
700   }
701 
GenReceiverForObjectAPI(const StructDef & struct_def,std::string * code_ptr)702   void GenReceiverForObjectAPI(const StructDef &struct_def,
703                                std::string *code_ptr) {
704     auto &code = *code_ptr;
705     code += GenIndents(1) + "# " + NormalizedName(struct_def) + "T";
706     code += GenIndents(1) + "def ";
707   }
708 
BeginClassForObjectAPI(const StructDef & struct_def,std::string * code_ptr)709   void BeginClassForObjectAPI(const StructDef &struct_def,
710                               std::string *code_ptr) {
711     auto &code = *code_ptr;
712     code += "\n";
713     code += "class " + NormalizedName(struct_def) + "T(object):";
714     code += "\n";
715   }
716 
717   // Gets the accoresponding python builtin type of a BaseType for scalars and
718   // string.
GetBasePythonTypeForScalarAndString(const BaseType & base_type)719   std::string GetBasePythonTypeForScalarAndString(const BaseType &base_type) {
720     if (IsBool(base_type)) {
721       return "bool";
722     } else if (IsFloat(base_type)) {
723       return "float";
724     } else if (IsInteger(base_type)) {
725       return "int";
726     } else if (base_type == BASE_TYPE_STRING) {
727       return "str";
728     } else {
729       FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
730       return "";
731     }
732   }
733 
GetDefaultValue(const FieldDef & field)734   std::string GetDefaultValue(const FieldDef &field) {
735     BaseType base_type = field.value.type.base_type;
736     if (IsBool(base_type)) {
737       return field.value.constant == "0" ? "False" : "True";
738     } else if (IsFloat(base_type)) {
739       return float_const_gen_.GenFloatConstant(field);
740     } else if (IsInteger(base_type)) {
741       return field.value.constant;
742     } else {
743       // For string, struct, and table.
744       return "None";
745     }
746   }
747 
GenUnionInit(const FieldDef & field,std::string * field_types_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)748   void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
749                     std::set<std::string> *import_list,
750                     std::set<std::string> *import_typing_list) {
751     // Gets all possible types in the union.
752     import_typing_list->insert("Union");
753     auto &field_types = *field_types_ptr;
754     field_types = "Union[";
755 
756     std::string separator_string = ", ";
757     auto enum_def = field.value.type.enum_def;
758     for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
759          ++it) {
760       auto &ev = **it;
761       // Union only supports string and table.
762       std::string field_type;
763       switch (ev.union_type.base_type) {
764         case BASE_TYPE_STRUCT:
765           field_type = GenTypeGet(ev.union_type) + "T";
766           if (parser_.opts.include_dependence_headers) {
767             auto package_reference = GenPackageReference(ev.union_type);
768             field_type = package_reference + "." + field_type;
769             import_list->insert("import " + package_reference);
770           }
771           break;
772         case BASE_TYPE_STRING: field_type += "str"; break;
773         case BASE_TYPE_NONE: field_type += "None"; break;
774         default: break;
775       }
776       field_types += field_type + separator_string;
777     }
778 
779     // Removes the last separator_string.
780     field_types.erase(field_types.length() - separator_string.size());
781     field_types += "]";
782 
783     // Gets the import lists for the union.
784     if (parser_.opts.include_dependence_headers) {
785       // The package reference is generated based on enum_def, instead
786       // of struct_def in field.type. That's why GenPackageReference() is
787       // not used.
788       Namespace *namespaces = field.value.type.enum_def->defined_namespace;
789       auto package_reference = namespaces->GetFullyQualifiedName(
790           MakeUpperCamel(*(field.value.type.enum_def)));
791       auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
792       import_list->insert("import " + package_reference);
793     }
794   }
795 
GenStructInit(const FieldDef & field,std::string * field_type_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)796   void GenStructInit(const FieldDef &field, std::string *field_type_ptr,
797                      std::set<std::string> *import_list,
798                      std::set<std::string> *import_typing_list) {
799     import_typing_list->insert("Optional");
800     auto &field_type = *field_type_ptr;
801     if (parser_.opts.include_dependence_headers) {
802       auto package_reference = GenPackageReference(field.value.type);
803       field_type = package_reference + "." + TypeName(field) + "T]";
804       import_list->insert("import " + package_reference);
805     } else {
806       field_type = TypeName(field) + "T]";
807     }
808     field_type = "Optional[" + field_type;
809   }
810 
GenVectorInit(const FieldDef & field,std::string * field_type_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list)811   void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
812                      std::set<std::string> *import_list,
813                      std::set<std::string> *import_typing_list) {
814     import_typing_list->insert("List");
815     auto &field_type = *field_type_ptr;
816     auto base_type = field.value.type.VectorType().base_type;
817     if (base_type == BASE_TYPE_STRUCT) {
818       field_type = GenTypeGet(field.value.type.VectorType()) + "T]";
819       if (parser_.opts.include_dependence_headers) {
820         auto package_reference =
821             GenPackageReference(field.value.type.VectorType());
822         field_type = package_reference + "." +
823                      GenTypeGet(field.value.type.VectorType()) + "T]";
824         import_list->insert("import " + package_reference);
825       }
826       field_type = "List[" + field_type;
827     } else {
828       field_type =
829           "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
830     }
831   }
832 
GenInitialize(const StructDef & struct_def,std::string * code_ptr,std::set<std::string> * import_list)833   void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
834                      std::set<std::string> *import_list) {
835     std::string code;
836     std::set<std::string> import_typing_list;
837     for (auto it = struct_def.fields.vec.begin();
838          it != struct_def.fields.vec.end(); ++it) {
839       auto &field = **it;
840       if (field.deprecated) continue;
841 
842       // Determines field type, default value, and typing imports.
843       auto base_type = field.value.type.base_type;
844       std::string field_type;
845       switch (base_type) {
846         case BASE_TYPE_UNION: {
847           GenUnionInit(field, &field_type, import_list, &import_typing_list);
848           break;
849         }
850         case BASE_TYPE_STRUCT: {
851           GenStructInit(field, &field_type, import_list, &import_typing_list);
852           break;
853         }
854         case BASE_TYPE_VECTOR:
855         case BASE_TYPE_ARRAY: {
856           GenVectorInit(field, &field_type, import_list, &import_typing_list);
857           break;
858         }
859         default:
860           // Scalar or sting fields.
861           field_type = GetBasePythonTypeForScalarAndString(base_type);
862           break;
863       }
864 
865       auto default_value = GetDefaultValue(field);
866       // Wrties the init statement.
867       auto field_instance_name = MakeLowerCamel(field);
868       code += GenIndents(2) + "self." + field_instance_name + " = " +
869               default_value + "  # type: " + field_type;
870     }
871 
872     // Writes __init__ method.
873     auto &code_base = *code_ptr;
874     GenReceiverForObjectAPI(struct_def, code_ptr);
875     code_base += "__init__(self):";
876     if (code.empty()) {
877       code_base += GenIndents(2) + "pass";
878     } else {
879       code_base += code;
880     }
881     code_base += "\n";
882 
883     // Merges the typing imports into import_list.
884     if (!import_typing_list.empty()) {
885       // Adds the try statement.
886       std::string typing_imports = "try:";
887       typing_imports += GenIndents(1) + "from typing import ";
888       std::string separator_string = ", ";
889       for (auto it = import_typing_list.begin(); it != import_typing_list.end();
890            ++it) {
891         const std::string &im = *it;
892         typing_imports += im + separator_string;
893       }
894       // Removes the last separator_string.
895       typing_imports.erase(typing_imports.length() - separator_string.size());
896 
897       // Adds the except statement.
898       typing_imports += "\n";
899       typing_imports += "except:";
900       typing_imports += GenIndents(1) + "pass";
901       import_list->insert(typing_imports);
902     }
903 
904     // Removes the import of the struct itself, if applied.
905     auto package_reference =
906         struct_def.defined_namespace->GetFullyQualifiedName(
907             MakeUpperCamel(struct_def));
908     auto struct_import = "import " + package_reference;
909     import_list->erase(struct_import);
910   }
911 
InitializeFromBuf(const StructDef & struct_def,std::string * code_ptr)912   void InitializeFromBuf(const StructDef &struct_def, std::string *code_ptr) {
913     auto &code = *code_ptr;
914     auto instance_name = MakeLowerCamel(struct_def);
915     auto struct_name = NormalizedName(struct_def);
916 
917     code += GenIndents(1) + "@classmethod";
918     code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
919     code += GenIndents(2) + instance_name + " = " + struct_name + "()";
920     code += GenIndents(2) + instance_name + ".Init(buf, pos)";
921     code += GenIndents(2) + "return cls.InitFromObj(" + instance_name + ")";
922     code += "\n";
923   }
924 
InitializeFromObjForObject(const StructDef & struct_def,std::string * code_ptr)925   void InitializeFromObjForObject(const StructDef &struct_def,
926                                   std::string *code_ptr) {
927     auto &code = *code_ptr;
928     auto instance_name = MakeLowerCamel(struct_def);
929     auto struct_name = NormalizedName(struct_def);
930 
931     code += GenIndents(1) + "@classmethod";
932     code += GenIndents(1) + "def InitFromObj(cls, " + instance_name + "):";
933     code += GenIndents(2) + "x = " + struct_name + "T()";
934     code += GenIndents(2) + "x._UnPack(" + instance_name + ")";
935     code += GenIndents(2) + "return x";
936     code += "\n";
937   }
938 
GenUnPackForStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)939   void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
940                           std::string *code_ptr) {
941     auto &code = *code_ptr;
942     auto struct_instance_name = MakeLowerCamel(struct_def);
943     auto field_instance_name = MakeLowerCamel(field);
944     auto field_accessor_name = MakeUpperCamel(field);
945     auto field_type = TypeName(field);
946 
947     if (parser_.opts.include_dependence_headers) {
948       auto package_reference = GenPackageReference(field.value.type);
949       field_type = package_reference + "." + TypeName(field);
950     }
951 
952     code += GenIndents(2) + "if " + struct_instance_name + "." +
953             field_accessor_name + "(";
954     // if field is a struct, we need to create an instance for it first.
955     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
956       code += field_type + "()";
957     }
958     code += ") is not None:";
959     code += GenIndents(3) + "self." + field_instance_name + " = " + field_type +
960             "T.InitFromObj(" + struct_instance_name + "." +
961             field_accessor_name + "(";
962     // A struct's accessor requires a struct buf instance.
963     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
964       code += field_type + "()";
965     }
966     code += "))";
967   }
968 
GenUnPackForUnion(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)969   void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
970                          std::string *code_ptr) {
971     auto &code = *code_ptr;
972     auto field_instance_name = MakeLowerCamel(field);
973     auto field_accessor_name = MakeUpperCamel(field);
974     auto struct_instance_name = MakeLowerCamel(struct_def);
975     auto union_name = MakeUpperCamel(*(field.value.type.enum_def));
976 
977     if (parser_.opts.include_dependence_headers) {
978       Namespace *namespaces = field.value.type.enum_def->defined_namespace;
979       auto package_reference = namespaces->GetFullyQualifiedName(
980           MakeUpperCamel(*(field.value.type.enum_def)));
981       union_name = package_reference + "." + union_name;
982     }
983     code += GenIndents(2) + "self." + field_instance_name + " = " + union_name +
984             "Creator(" + "self." + field_instance_name + "Type, " +
985             struct_instance_name + "." + field_accessor_name + "())";
986   }
987 
GenUnPackForStructVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)988   void GenUnPackForStructVector(const StructDef &struct_def,
989                                 const FieldDef &field, std::string *code_ptr) {
990     auto &code = *code_ptr;
991     auto field_instance_name = MakeLowerCamel(field);
992     auto field_accessor_name = MakeUpperCamel(field);
993     auto struct_instance_name = MakeLowerCamel(struct_def);
994 
995     code += GenIndents(2) + "if not " + struct_instance_name + "." +
996             field_accessor_name + "IsNone():";
997     code += GenIndents(3) + "self." + field_instance_name + " = []";
998     code += GenIndents(3) + "for i in range(" + struct_instance_name + "." +
999             field_accessor_name + "Length()):";
1000 
1001     auto field_type_name = TypeName(field);
1002     auto one_instance = field_type_name + "_";
1003     one_instance[0] = char(tolower(one_instance[0]));
1004 
1005     if (parser_.opts.include_dependence_headers) {
1006       auto package_reference = GenPackageReference(field.value.type);
1007       field_type_name = package_reference + "." + TypeName(field);
1008     }
1009 
1010     code += GenIndents(4) + "if " + struct_instance_name + "." +
1011             field_accessor_name + "(i) is None:";
1012     code += GenIndents(5) + "self." + field_instance_name + ".append(None)";
1013     code += GenIndents(4) + "else:";
1014     code += GenIndents(5) + one_instance + " = " + field_type_name +
1015             "T.InitFromObj(" + struct_instance_name + "." +
1016             field_accessor_name + "(i))";
1017     code += GenIndents(5) + "self." + field_instance_name + ".append(" +
1018             one_instance + ")";
1019   }
1020 
GenUnpackforScalarVectorHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents)1021   void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
1022                                       const FieldDef &field,
1023                                       std::string *code_ptr, int indents) {
1024     auto &code = *code_ptr;
1025     auto field_instance_name = MakeLowerCamel(field);
1026     auto field_accessor_name = MakeUpperCamel(field);
1027     auto struct_instance_name = MakeLowerCamel(struct_def);
1028 
1029     code += GenIndents(indents) + "self." + field_instance_name + " = []";
1030     code += GenIndents(indents) + "for i in range(" + struct_instance_name +
1031             "." + field_accessor_name + "Length()):";
1032     code += GenIndents(indents + 1) + "self." + field_instance_name +
1033             ".append(" + struct_instance_name + "." + field_accessor_name +
1034             "(i))";
1035   }
1036 
GenUnPackForScalarVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1037   void GenUnPackForScalarVector(const StructDef &struct_def,
1038                                 const FieldDef &field, std::string *code_ptr) {
1039     auto &code = *code_ptr;
1040     auto field_instance_name = MakeLowerCamel(field);
1041     auto field_accessor_name = MakeUpperCamel(field);
1042     auto struct_instance_name = MakeLowerCamel(struct_def);
1043 
1044     code += GenIndents(2) + "if not " + struct_instance_name + "." +
1045             field_accessor_name + "IsNone():";
1046 
1047     // String does not have the AsNumpy method.
1048     if (!(IsScalar(field.value.type.VectorType().base_type))) {
1049       GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
1050       return;
1051     }
1052 
1053     code += GenIndents(3) + "if np is None:";
1054     GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
1055 
1056     // If numpy exists, use the AsNumpy method to optimize the unpack speed.
1057     code += GenIndents(3) + "else:";
1058     code += GenIndents(4) + "self." + field_instance_name + " = " +
1059             struct_instance_name + "." + field_accessor_name + "AsNumpy()";
1060   }
1061 
GenUnPackForScalar(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr)1062   void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
1063                           std::string *code_ptr) {
1064     auto &code = *code_ptr;
1065     auto field_instance_name = MakeLowerCamel(field);
1066     auto field_accessor_name = MakeUpperCamel(field);
1067     auto struct_instance_name = MakeLowerCamel(struct_def);
1068 
1069     code += GenIndents(2) + "self." + field_instance_name + " = " +
1070             struct_instance_name + "." + field_accessor_name + "()";
1071   }
1072 
1073   // Generates the UnPack method for the object class.
GenUnPack(const StructDef & struct_def,std::string * code_ptr)1074   void GenUnPack(const StructDef &struct_def, std::string *code_ptr) {
1075     std::string code;
1076     // Items that needs to be imported. No duplicate modules will be imported.
1077     std::set<std::string> import_list;
1078 
1079     for (auto it = struct_def.fields.vec.begin();
1080          it != struct_def.fields.vec.end(); ++it) {
1081       auto &field = **it;
1082       if (field.deprecated) continue;
1083 
1084       auto field_type = TypeName(field);
1085       switch (field.value.type.base_type) {
1086         case BASE_TYPE_STRUCT: {
1087           GenUnPackForStruct(struct_def, field, &code);
1088           break;
1089         }
1090         case BASE_TYPE_UNION: {
1091           GenUnPackForUnion(struct_def, field, &code);
1092           break;
1093         }
1094         case BASE_TYPE_VECTOR: {
1095           auto vectortype = field.value.type.VectorType();
1096           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1097             GenUnPackForStructVector(struct_def, field, &code);
1098           } else {
1099             GenUnPackForScalarVector(struct_def, field, &code);
1100           }
1101           break;
1102         }
1103         case BASE_TYPE_ARRAY: {
1104           GenUnPackForScalarVector(struct_def, field, &code);
1105           break;
1106         }
1107         default: GenUnPackForScalar(struct_def, field, &code);
1108       }
1109     }
1110 
1111     // Writes import statements and code into the generated file.
1112     auto &code_base = *code_ptr;
1113     auto struct_instance_name = MakeLowerCamel(struct_def);
1114     auto struct_name = MakeUpperCamel(struct_def);
1115 
1116     GenReceiverForObjectAPI(struct_def, code_ptr);
1117     code_base += "_UnPack(self, " + struct_instance_name + "):";
1118     code_base += GenIndents(2) + "if " + struct_instance_name + " is None:";
1119     code_base += GenIndents(3) + "return";
1120 
1121     // Write the import statements.
1122     for (std::set<std::string>::iterator it = import_list.begin();
1123          it != import_list.end(); ++it) {
1124       code_base += GenIndents(2) + *it;
1125     }
1126 
1127     // Write the code.
1128     code_base += code;
1129     code_base += "\n";
1130   }
1131 
GenPackForStruct(const StructDef & struct_def,std::string * code_ptr)1132   void GenPackForStruct(const StructDef &struct_def, std::string *code_ptr) {
1133     auto &code = *code_ptr;
1134     auto struct_name = MakeUpperCamel(struct_def);
1135 
1136     GenReceiverForObjectAPI(struct_def, code_ptr);
1137     code += "Pack(self, builder):";
1138     code += GenIndents(2) + "return Create" + struct_name + "(builder";
1139 
1140     StructBuilderArgs(struct_def,
1141                       /* nameprefix = */ "self.",
1142                       /* namesuffix = */ "",
1143                       /* has_field_name = */ true,
1144                       /* fieldname_suffix = */ ".", code_ptr);
1145     code += ")\n";
1146   }
1147 
GenPackForStructVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1148   void GenPackForStructVectorField(const StructDef &struct_def,
1149                                    const FieldDef &field,
1150                                    std::string *code_prefix_ptr,
1151                                    std::string *code_ptr) {
1152     auto &code_prefix = *code_prefix_ptr;
1153     auto &code = *code_ptr;
1154     auto field_instance_name = MakeLowerCamel(field);
1155     auto struct_name = NormalizedName(struct_def);
1156     auto field_accessor_name = MakeUpperCamel(field);
1157 
1158     // Creates the field.
1159     code_prefix +=
1160         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1161     if (field.value.type.struct_def->fixed) {
1162       code_prefix += GenIndents(3) + struct_name + "Start" +
1163                      field_accessor_name + "Vector(builder, len(self." +
1164                      field_instance_name + "))";
1165       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1166                      field_instance_name + "))):";
1167       code_prefix +=
1168           GenIndents(4) + "self." + field_instance_name + "[i].Pack(builder)";
1169       code_prefix += GenIndents(3) + field_instance_name +
1170                      " = builder.EndVector(len(self." + field_instance_name +
1171                      "))";
1172     } else {
1173       // If the vector is a struct vector, we need to first build accessor for
1174       // each struct element.
1175       code_prefix += GenIndents(3) + field_instance_name + "list = []";
1176       code_prefix += GenIndents(3);
1177       code_prefix += "for i in range(len(self." + field_instance_name + ")):";
1178       code_prefix += GenIndents(4) + field_instance_name + "list.append(self." +
1179                      field_instance_name + "[i].Pack(builder))";
1180 
1181       code_prefix += GenIndents(3) + struct_name + "Start" +
1182                      field_accessor_name + "Vector(builder, len(self." +
1183                      field_instance_name + "))";
1184       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
1185                      field_instance_name + "))):";
1186       code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
1187                      field_instance_name + "list[i])";
1188       code_prefix += GenIndents(3) + field_instance_name +
1189                      " = builder.EndVector(len(self." + field_instance_name +
1190                      "))";
1191     }
1192 
1193     // Adds the field into the struct.
1194     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1195     code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1196             "(builder, " + field_instance_name + ")";
1197   }
1198 
GenPackForScalarVectorFieldHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents)1199   void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
1200                                          const FieldDef &field,
1201                                          std::string *code_ptr, int indents) {
1202     auto &code = *code_ptr;
1203     auto field_instance_name = MakeLowerCamel(field);
1204     auto field_accessor_name = MakeUpperCamel(field);
1205     auto struct_name = NormalizedName(struct_def);
1206     auto vectortype = field.value.type.VectorType();
1207 
1208     code += GenIndents(indents) + struct_name + "Start" + field_accessor_name +
1209             "Vector(builder, len(self." + field_instance_name + "))";
1210     code += GenIndents(indents) + "for i in reversed(range(len(self." +
1211             field_instance_name + "))):";
1212     code += GenIndents(indents + 1) + "builder.Prepend";
1213 
1214     std::string type_name;
1215     switch (vectortype.base_type) {
1216       case BASE_TYPE_BOOL: type_name = "Bool"; break;
1217       case BASE_TYPE_CHAR: type_name = "Byte"; break;
1218       case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
1219       case BASE_TYPE_SHORT: type_name = "Int16"; break;
1220       case BASE_TYPE_USHORT: type_name = "Uint16"; break;
1221       case BASE_TYPE_INT: type_name = "Int32"; break;
1222       case BASE_TYPE_UINT: type_name = "Uint32"; break;
1223       case BASE_TYPE_LONG: type_name = "Int64"; break;
1224       case BASE_TYPE_ULONG: type_name = "Uint64"; break;
1225       case BASE_TYPE_FLOAT: type_name = "Float32"; break;
1226       case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
1227       case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
1228       default: type_name = "VOffsetT"; break;
1229     }
1230     code += type_name;
1231   }
1232 
GenPackForScalarVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1233   void GenPackForScalarVectorField(const StructDef &struct_def,
1234                                    const FieldDef &field,
1235                                    std::string *code_prefix_ptr,
1236                                    std::string *code_ptr) {
1237     auto &code = *code_ptr;
1238     auto &code_prefix = *code_prefix_ptr;
1239     auto field_instance_name = MakeLowerCamel(field);
1240     auto field_accessor_name = MakeUpperCamel(field);
1241     auto struct_name = NormalizedName(struct_def);
1242 
1243     // Adds the field into the struct.
1244     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1245     code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1246             "(builder, " + field_instance_name + ")";
1247 
1248     // Creates the field.
1249     code_prefix +=
1250         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1251     // If the vector is a string vector, we need to first build accessor for
1252     // each string element. And this generated code, needs to be
1253     // placed ahead of code_prefix.
1254     auto vectortype = field.value.type.VectorType();
1255     if (vectortype.base_type == BASE_TYPE_STRING) {
1256       code_prefix += GenIndents(3) + MakeLowerCamel(field) + "list = []";
1257       code_prefix += GenIndents(3) + "for i in range(len(self." +
1258                      field_instance_name + ")):";
1259       code_prefix += GenIndents(4) + MakeLowerCamel(field) +
1260                      "list.append(builder.CreateString(self." +
1261                      field_instance_name + "[i]))";
1262       GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
1263       code_prefix += "(" + MakeLowerCamel(field) + "list[i])";
1264       code_prefix += GenIndents(3) + field_instance_name +
1265                      " = builder.EndVector(len(self." + field_instance_name +
1266                      "))";
1267       return;
1268     }
1269 
1270     code_prefix += GenIndents(3) + "if np is not None and type(self." +
1271                    field_instance_name + ") is np.ndarray:";
1272     code_prefix += GenIndents(4) + field_instance_name +
1273                    " = builder.CreateNumpyVector(self." + field_instance_name +
1274                    ")";
1275     code_prefix += GenIndents(3) + "else:";
1276     GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
1277     code_prefix += "(self." + field_instance_name + "[i])";
1278     code_prefix += GenIndents(4) + field_instance_name +
1279                    " = builder.EndVector(len(self." + field_instance_name +
1280                    "))";
1281   }
1282 
GenPackForStructField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1283   void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
1284                              std::string *code_prefix_ptr,
1285                              std::string *code_ptr) {
1286     auto &code_prefix = *code_prefix_ptr;
1287     auto &code = *code_ptr;
1288     auto field_instance_name = MakeLowerCamel(field);
1289 
1290     auto field_accessor_name = MakeUpperCamel(field);
1291     auto struct_name = NormalizedName(struct_def);
1292 
1293     if (field.value.type.struct_def->fixed) {
1294       // Pure struct fields need to be created along with their parent
1295       // structs.
1296       code +=
1297           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1298       code += GenIndents(3) + field_instance_name + " = self." +
1299               field_instance_name + ".Pack(builder)";
1300     } else {
1301       // Tables need to be created before their parent structs are created.
1302       code_prefix +=
1303           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1304       code_prefix += GenIndents(3) + field_instance_name + " = self." +
1305                      field_instance_name + ".Pack(builder)";
1306       code +=
1307           GenIndents(2) + "if self." + field_instance_name + " is not None:";
1308     }
1309 
1310     code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1311             "(builder, " + field_instance_name + ")";
1312   }
1313 
GenPackForUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr)1314   void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
1315                             std::string *code_prefix_ptr,
1316                             std::string *code_ptr) {
1317     auto &code_prefix = *code_prefix_ptr;
1318     auto &code = *code_ptr;
1319     auto field_instance_name = MakeLowerCamel(field);
1320 
1321     auto field_accessor_name = MakeUpperCamel(field);
1322     auto struct_name = NormalizedName(struct_def);
1323 
1324     // TODO(luwa): TypeT should be moved under the None check as well.
1325     code_prefix +=
1326         GenIndents(2) + "if self." + field_instance_name + " is not None:";
1327     code_prefix += GenIndents(3) + field_instance_name + " = self." +
1328                    field_instance_name + ".Pack(builder)";
1329     code += GenIndents(2) + "if self." + field_instance_name + " is not None:";
1330     code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1331             "(builder, " + field_instance_name + ")";
1332   }
1333 
GenPackForTable(const StructDef & struct_def,std::string * code_ptr)1334   void GenPackForTable(const StructDef &struct_def, std::string *code_ptr) {
1335     auto &code_base = *code_ptr;
1336     std::string code, code_prefix;
1337     auto struct_instance_name = MakeLowerCamel(struct_def);
1338     auto struct_name = NormalizedName(struct_def);
1339 
1340     GenReceiverForObjectAPI(struct_def, code_ptr);
1341     code_base += "Pack(self, builder):";
1342     code += GenIndents(2) + struct_name + "Start(builder)";
1343     for (auto it = struct_def.fields.vec.begin();
1344          it != struct_def.fields.vec.end(); ++it) {
1345       auto &field = **it;
1346       if (field.deprecated) continue;
1347 
1348       auto field_accessor_name = MakeUpperCamel(field);
1349       auto field_instance_name = MakeLowerCamel(field);
1350 
1351       switch (field.value.type.base_type) {
1352         case BASE_TYPE_STRUCT: {
1353           GenPackForStructField(struct_def, field, &code_prefix, &code);
1354           break;
1355         }
1356         case BASE_TYPE_UNION: {
1357           GenPackForUnionField(struct_def, field, &code_prefix, &code);
1358           break;
1359         }
1360         case BASE_TYPE_VECTOR: {
1361           auto vectortype = field.value.type.VectorType();
1362           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1363             GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
1364           } else {
1365             GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1366           }
1367           break;
1368         }
1369         case BASE_TYPE_ARRAY: {
1370           GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
1371           break;
1372         }
1373         case BASE_TYPE_STRING: {
1374           code_prefix += GenIndents(2) + "if self." + field_instance_name +
1375                          " is not None:";
1376           code_prefix += GenIndents(3) + field_instance_name +
1377                          " = builder.CreateString(self." + field_instance_name +
1378                          ")";
1379           code += GenIndents(2) + "if self." + field_instance_name +
1380                   " is not None:";
1381           code += GenIndents(3) + struct_name + "Add" + field_accessor_name +
1382                   "(builder, " + field_instance_name + ")";
1383           break;
1384         }
1385         default:
1386           // Generates code for scalar values. If the value equals to the
1387           // default value, builder will automatically ignore it. So we don't
1388           // need to check the value ahead.
1389           code += GenIndents(2) + struct_name + "Add" + field_accessor_name +
1390                   "(builder, self." + field_instance_name + ")";
1391           break;
1392       }
1393     }
1394 
1395     code += GenIndents(2) + struct_instance_name + " = " + struct_name +
1396             "End(builder)";
1397     code += GenIndents(2) + "return " + struct_instance_name;
1398 
1399     code_base += code_prefix + code;
1400     code_base += "\n";
1401   }
1402 
GenStructForObjectAPI(const StructDef & struct_def,std::string * code_ptr)1403   void GenStructForObjectAPI(const StructDef &struct_def,
1404                              std::string *code_ptr) {
1405     if (struct_def.generated) return;
1406 
1407     std::set<std::string> import_list;
1408     std::string code;
1409 
1410     // Creates an object class for a struct or a table
1411     BeginClassForObjectAPI(struct_def, &code);
1412 
1413     GenInitialize(struct_def, &code, &import_list);
1414 
1415     InitializeFromBuf(struct_def, &code);
1416 
1417     InitializeFromObjForObject(struct_def, &code);
1418 
1419     GenUnPack(struct_def, &code);
1420 
1421     if (struct_def.fixed) {
1422       GenPackForStruct(struct_def, &code);
1423     } else {
1424       GenPackForTable(struct_def, &code);
1425     }
1426 
1427     // Adds the imports at top.
1428     auto &code_base = *code_ptr;
1429     code_base += "\n";
1430     for (auto it = import_list.begin(); it != import_list.end(); it++) {
1431       auto im = *it;
1432       code_base += im + "\n";
1433     }
1434     code_base += code;
1435   }
1436 
GenUnionCreatorForStruct(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)1437   void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
1438                                 std::string *code_ptr) {
1439     auto &code = *code_ptr;
1440     auto union_name = NormalizedName(enum_def);
1441     auto field_name = NormalizedName(ev);
1442     auto field_type = GenTypeGet(ev.union_type) + "T";
1443 
1444     code += GenIndents(1) + "if unionType == " + union_name + "()." +
1445             field_name + ":";
1446     if (parser_.opts.include_dependence_headers) {
1447       auto package_reference = GenPackageReference(ev.union_type);
1448       code += GenIndents(2) + "import " + package_reference;
1449       field_type = package_reference + "." + field_type;
1450     }
1451     code += GenIndents(2) + "return " + field_type +
1452             ".InitFromBuf(table.Bytes, table.Pos)";
1453   }
1454 
GenUnionCreatorForString(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr)1455   void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
1456                                 std::string *code_ptr) {
1457     auto &code = *code_ptr;
1458     auto union_name = NormalizedName(enum_def);
1459     auto field_name = NormalizedName(ev);
1460 
1461     code += GenIndents(1) + "if unionType == " + union_name + "()." +
1462             field_name + ":";
1463     code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
1464     code += GenIndents(2) + "union = tab.String(table.Pos)";
1465     code += GenIndents(2) + "return union";
1466   }
1467 
1468   // Creates an union object based on union type.
GenUnionCreator(const EnumDef & enum_def,std::string * code_ptr)1469   void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) {
1470     auto &code = *code_ptr;
1471     auto union_name = MakeUpperCamel(enum_def);
1472 
1473     code += "\n";
1474     code += "def " + union_name + "Creator(unionType, table):";
1475     code += GenIndents(1) + "from flatbuffers.table import Table";
1476     code += GenIndents(1) + "if not isinstance(table, Table):";
1477     code += GenIndents(2) + "return None";
1478 
1479     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1480       auto &ev = **it;
1481       // Union only supports string and table.
1482       switch (ev.union_type.base_type) {
1483         case BASE_TYPE_STRUCT:
1484           GenUnionCreatorForStruct(enum_def, ev, &code);
1485           break;
1486         case BASE_TYPE_STRING:
1487           GenUnionCreatorForString(enum_def, ev, &code);
1488           break;
1489         default: break;
1490       }
1491     }
1492     code += GenIndents(1) + "return None";
1493     code += "\n";
1494   }
1495 
1496   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr)1497   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
1498     if (enum_def.generated) return;
1499 
1500     GenComment(enum_def.doc_comment, code_ptr, &def_comment);
1501     BeginEnum(NormalizedName(enum_def), code_ptr);
1502     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
1503       auto &ev = **it;
1504       GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
1505       EnumMember(enum_def, ev, code_ptr);
1506     }
1507     EndEnum(code_ptr);
1508   }
1509 
1510   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type)1511   std::string GenGetter(const Type &type) {
1512     switch (type.base_type) {
1513       case BASE_TYPE_STRING: return "self._tab.String(";
1514       case BASE_TYPE_UNION: return "self._tab.Union(";
1515       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
1516       default:
1517         return "self._tab.Get(flatbuffers.number_types." +
1518                MakeCamel(GenTypeGet(type)) + "Flags, ";
1519     }
1520   }
1521 
1522   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field)1523   std::string GenMethod(const FieldDef &field) {
1524     return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
1525                ? MakeCamel(GenTypeBasic(field.value.type))
1526                : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
1527   }
1528 
GenTypeBasic(const Type & type)1529   std::string GenTypeBasic(const Type &type) {
1530     // clang-format off
1531     static const char *ctypename[] = {
1532       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
1533               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
1534         #PTYPE,
1535         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
1536       #undef FLATBUFFERS_TD
1537     };
1538     // clang-format on
1539     return ctypename[IsArray(type) ? type.VectorType().base_type
1540                                    : type.base_type];
1541   }
1542 
GenTypePointer(const Type & type)1543   std::string GenTypePointer(const Type &type) {
1544     switch (type.base_type) {
1545       case BASE_TYPE_STRING: return "string";
1546       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
1547       case BASE_TYPE_STRUCT: return type.struct_def->name;
1548       case BASE_TYPE_UNION:
1549         // fall through
1550       default: return "*flatbuffers.Table";
1551     }
1552   }
1553 
GenTypeGet(const Type & type)1554   std::string GenTypeGet(const Type &type) {
1555     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
1556   }
1557 
TypeName(const FieldDef & field)1558   std::string TypeName(const FieldDef &field) {
1559     return GenTypeGet(field.value.type);
1560   }
1561 
1562   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr)1563   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
1564     BeginBuilderArgs(struct_def, code_ptr);
1565     StructBuilderArgs(struct_def,
1566                       /* nameprefix = */ "",
1567                       /* namesuffix = */ "",
1568                       /* has_field_name = */ true,
1569                       /* fieldname_suffix = */ "_", code_ptr);
1570     EndBuilderArgs(code_ptr);
1571 
1572     StructBuilderBody(struct_def, "", code_ptr);
1573     EndBuilderBody(code_ptr);
1574   }
1575 
generate()1576   bool generate() {
1577     if (!generateEnums()) return false;
1578     if (!generateStructs()) return false;
1579     return true;
1580   }
1581 
1582  private:
generateEnums()1583   bool generateEnums() {
1584     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
1585          ++it) {
1586       auto &enum_def = **it;
1587       std::string enumcode;
1588       GenEnum(enum_def, &enumcode);
1589       if (parser_.opts.generate_object_based_api & enum_def.is_union) {
1590         GenUnionCreator(enum_def, &enumcode);
1591       }
1592       if (!SaveType(enum_def, enumcode, false)) return false;
1593     }
1594     return true;
1595   }
1596 
generateStructs()1597   bool generateStructs() {
1598     for (auto it = parser_.structs_.vec.begin();
1599          it != parser_.structs_.vec.end(); ++it) {
1600       auto &struct_def = **it;
1601       std::string declcode;
1602       GenStruct(struct_def, &declcode);
1603       if (parser_.opts.generate_object_based_api) {
1604         GenStructForObjectAPI(struct_def, &declcode);
1605       }
1606       if (!SaveType(struct_def, declcode, true)) return false;
1607     }
1608     return true;
1609   }
1610 
1611   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr)1612   void BeginFile(const std::string &name_space_name, const bool needs_imports,
1613                  std::string *code_ptr) {
1614     auto &code = *code_ptr;
1615     code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
1616     code += "# namespace: " + name_space_name + "\n\n";
1617     if (needs_imports) {
1618       code += "import flatbuffers\n";
1619       code += "from flatbuffers.compat import import_numpy\n";
1620       code += "np = import_numpy()\n\n";
1621     }
1622   }
1623 
1624   // Save out the generated code for a Python Table type.
SaveType(const Definition & def,const std::string & classcode,bool needs_imports)1625   bool SaveType(const Definition &def, const std::string &classcode,
1626                 bool needs_imports) {
1627     if (!classcode.length()) return true;
1628 
1629     std::string namespace_dir = path_;
1630     auto &namespaces = def.defined_namespace->components;
1631     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
1632       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
1633       namespace_dir += *it;
1634       std::string init_py_filename = namespace_dir + "/__init__.py";
1635       SaveFile(init_py_filename.c_str(), "", false);
1636     }
1637 
1638     std::string code = "";
1639     BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
1640     code += classcode;
1641     std::string filename =
1642         NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
1643     return SaveFile(filename.c_str(), code, false);
1644   }
1645 
1646  private:
1647   std::unordered_set<std::string> keywords_;
1648   const SimpleFloatConstantGenerator float_const_gen_;
1649 };
1650 
1651 }  // namespace python
1652 
GeneratePython(const Parser & parser,const std::string & path,const std::string & file_name)1653 bool GeneratePython(const Parser &parser, const std::string &path,
1654                     const std::string &file_name) {
1655   python::PythonGenerator generator(parser, path, file_name);
1656   return generator.generate();
1657 }
1658 
1659 }  // namespace flatbuffers
1660