[C++] Refactor to conform to Google C++ style guide (#5608)
[platform/upstream/flatbuffers.git] / src / idl_gen_python.cpp
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 <string>
20 #include <unordered_set>
21
22 #include "flatbuffers/code_generators.h"
23 #include "flatbuffers/flatbuffers.h"
24 #include "flatbuffers/idl.h"
25 #include "flatbuffers/util.h"
26
27 namespace flatbuffers {
28 namespace python {
29
30 // Hardcode spaces per indentation.
31 const CommentConfig def_comment = { nullptr, "#", nullptr };
32 const std::string Indent = "    ";
33
34 class PythonGenerator : public BaseGenerator {
35  public:
36   PythonGenerator(const Parser &parser, const std::string &path,
37                   const std::string &file_name)
38       : BaseGenerator(parser, path, file_name, "" /* not used */,
39                       "" /* not used */),
40         float_const_gen_("float('nan')", "float('inf')", "float('-inf')") {
41     static const char *const keywords[] = {
42       "False",   "None",     "True",     "and",    "as",   "assert", "break",
43       "class",   "continue", "def",      "del",    "elif", "else",   "except",
44       "finally", "for",      "from",     "global", "if",   "import", "in",
45       "is",      "lambda",   "nonlocal", "not",    "or",   "pass",   "raise",
46       "return",  "try",      "while",    "with",   "yield"
47     };
48     keywords_.insert(std::begin(keywords), std::end(keywords));
49   }
50
51   // Most field accessors need to retrieve and test the field offset first,
52   // this is the prefix code for that.
53   std::string OffsetPrefix(const FieldDef &field) {
54     return "\n" + Indent + Indent +
55            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
56            "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
57            Indent + Indent + "if o != 0:\n";
58   }
59
60   // Begin a class declaration.
61   void BeginClass(const StructDef &struct_def, std::string *code_ptr) {
62     std::string &code = *code_ptr;
63     code += "class " + NormalizedName(struct_def) + "(object):\n";
64     code += Indent + "__slots__ = ['_tab']";
65     code += "\n\n";
66   }
67
68   // Begin enum code with a class declaration.
69   void BeginEnum(const std::string &class_name, std::string *code_ptr) {
70     std::string &code = *code_ptr;
71     code += "class " + class_name + "(object):\n";
72   }
73
74   std::string EscapeKeyword(const std::string &name) const {
75     return keywords_.find(name) == keywords_.end() ? name : name + "_";
76   }
77
78   std::string NormalizedName(const Definition &definition) const {
79     return EscapeKeyword(definition.name);
80   }
81
82   std::string NormalizedName(const EnumVal &ev) const {
83     return EscapeKeyword(ev.name);
84   }
85
86   // A single enum member.
87   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
88                   std::string *code_ptr) {
89     std::string &code = *code_ptr;
90     code += Indent;
91     code += NormalizedName(ev);
92     code += " = ";
93     code += enum_def.ToString(ev) + "\n";
94   }
95
96   // End enum code.
97   void EndEnum(std::string *code_ptr) {
98     std::string &code = *code_ptr;
99     code += "\n";
100   }
101
102   // Initialize a new struct or table from existing data.
103   void NewRootTypeFromBuffer(const StructDef &struct_def,
104                              std::string *code_ptr) {
105     std::string &code = *code_ptr;
106
107     code += Indent + "@classmethod\n";
108     code += Indent + "def GetRootAs";
109     code += NormalizedName(struct_def);
110     code += "(cls, buf, offset):";
111     code += "\n";
112     code += Indent + Indent;
113     code += "n = flatbuffers.encode.Get";
114     code += "(flatbuffers.packer.uoffset, buf, offset)\n";
115     code += Indent + Indent + "x = " + NormalizedName(struct_def) + "()\n";
116     code += Indent + Indent + "x.Init(buf, n + offset)\n";
117     code += Indent + Indent + "return x\n";
118     code += "\n";
119   }
120
121   // Initialize an existing object with other data, to avoid an allocation.
122   void InitializeExisting(const StructDef &struct_def, std::string *code_ptr) {
123     std::string &code = *code_ptr;
124
125     GenReceiver(struct_def, code_ptr);
126     code += "Init(self, buf, pos):\n";
127     code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
128     code += "\n";
129   }
130
131   // Get the length of a vector.
132   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
133                     std::string *code_ptr) {
134     std::string &code = *code_ptr;
135
136     GenReceiver(struct_def, code_ptr);
137     code += MakeCamel(NormalizedName(field)) + "Length(self";
138     code += "):" + OffsetPrefix(field);
139     code += Indent + Indent + Indent + "return self._tab.VectorLen(o)\n";
140     code += Indent + Indent + "return 0\n\n";
141   }
142
143   // Get the value of a struct's scalar.
144   void GetScalarFieldOfStruct(const StructDef &struct_def,
145                               const FieldDef &field, std::string *code_ptr) {
146     std::string &code = *code_ptr;
147     std::string getter = GenGetter(field.value.type);
148     GenReceiver(struct_def, code_ptr);
149     code += MakeCamel(NormalizedName(field));
150     code += "(self): return " + getter;
151     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
152     code += NumToString(field.value.offset) + "))\n";
153   }
154
155   // Get the value of a table's scalar.
156   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
157                              std::string *code_ptr) {
158     std::string &code = *code_ptr;
159     std::string getter = GenGetter(field.value.type);
160     GenReceiver(struct_def, code_ptr);
161     code += MakeCamel(NormalizedName(field));
162     code += "(self):";
163     code += OffsetPrefix(field);
164     getter += "o + self._tab.Pos)";
165     auto is_bool = IsBool(field.value.type.base_type);
166     if (is_bool) { getter = "bool(" + getter + ")"; }
167     code += Indent + Indent + Indent + "return " + getter + "\n";
168     std::string default_value;
169     if (is_bool) {
170       default_value = field.value.constant == "0" ? "False" : "True";
171     } else {
172       default_value = IsFloat(field.value.type.base_type)
173                           ? float_const_gen_.GenFloatConstant(field)
174                           : field.value.constant;
175     }
176     code += Indent + Indent + "return " + default_value + "\n\n";
177   }
178
179   // Get a struct by initializing an existing struct.
180   // Specific to Struct.
181   void GetStructFieldOfStruct(const StructDef &struct_def,
182                               const FieldDef &field, std::string *code_ptr) {
183     std::string &code = *code_ptr;
184     GenReceiver(struct_def, code_ptr);
185     code += MakeCamel(NormalizedName(field));
186     code += "(self, obj):\n";
187     code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
188     code += NumToString(field.value.offset) + ")";
189     code += "\n" + Indent + Indent + "return obj\n\n";
190   }
191
192   // Get the value of a fixed size array.
193   void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
194                         std::string *code_ptr) {
195     std::string &code = *code_ptr;
196     const auto vec_type = field.value.type.VectorType();
197     GenReceiver(struct_def, code_ptr);
198     code += MakeCamel(NormalizedName(field));
199     if (IsStruct(vec_type)) {
200       code += "(self, obj, i):\n";
201       code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
202       code += NumToString(field.value.offset) + " + i * ";
203       code += NumToString(InlineSize(vec_type));
204       code += ")\n" + Indent + Indent + "return obj\n\n";
205     } else {
206       auto getter = GenGetter(vec_type);
207       code += "(self): return [" + getter;
208       code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
209       code += NumToString(field.value.offset) + " + i * ";
210       code += NumToString(InlineSize(vec_type));
211       code += ")) for i in range(";
212       code += NumToString(field.value.type.fixed_length) + ")]\n";
213     }
214   }
215
216   // Get a struct by initializing an existing struct.
217   // Specific to Table.
218   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
219                              std::string *code_ptr) {
220     std::string &code = *code_ptr;
221     GenReceiver(struct_def, code_ptr);
222     code += MakeCamel(NormalizedName(field));
223     code += "(self):";
224     code += OffsetPrefix(field);
225     if (field.value.type.struct_def->fixed) {
226       code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
227     } else {
228       code += Indent + Indent + Indent;
229       code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
230     }
231     code += Indent + Indent + Indent;
232     code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
233     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
234     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
235     code += Indent + Indent + Indent + "return obj\n";
236     code += Indent + Indent + "return None\n\n";
237   }
238
239   // Get the value of a string.
240   void GetStringField(const StructDef &struct_def, const FieldDef &field,
241                       std::string *code_ptr) {
242     std::string &code = *code_ptr;
243     GenReceiver(struct_def, code_ptr);
244     code += MakeCamel(NormalizedName(field));
245     code += "(self):";
246     code += OffsetPrefix(field);
247     code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
248     code += "o + self._tab.Pos)\n";
249     code += Indent + Indent + "return None\n\n";
250   }
251
252   // Get the value of a union from an object.
253   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
254                      std::string *code_ptr) {
255     std::string &code = *code_ptr;
256     GenReceiver(struct_def, code_ptr);
257     code += MakeCamel(NormalizedName(field)) + "(self):";
258     code += OffsetPrefix(field);
259
260     // TODO(rw): this works and is not the good way to it:
261     bool is_native_table = TypeName(field) == "*flatbuffers.Table";
262     if (is_native_table) {
263       code +=
264           Indent + Indent + Indent + "from flatbuffers.table import Table\n";
265     } else {
266       code += Indent + Indent + Indent;
267       code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
268     }
269     code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
270     code += Indent + Indent + Indent + GenGetter(field.value.type);
271     code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
272     code += Indent + Indent + "return None\n\n";
273   }
274
275   // Get the value of a vector's struct member.
276   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
277                                  const FieldDef &field, std::string *code_ptr) {
278     std::string &code = *code_ptr;
279     auto vectortype = field.value.type.VectorType();
280
281     GenReceiver(struct_def, code_ptr);
282     code += MakeCamel(NormalizedName(field));
283     code += "(self, j):" + OffsetPrefix(field);
284     code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
285     code += Indent + Indent + Indent;
286     code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
287     code += NumToString(InlineSize(vectortype)) + "\n";
288     if (!(vectortype.struct_def->fixed)) {
289       code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
290     }
291     code += Indent + Indent + Indent;
292     code += "from ." + TypeName(field) + " import " + TypeName(field) + "\n";
293     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
294     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
295     code += Indent + Indent + Indent + "return obj\n";
296     code += Indent + Indent + "return None\n\n";
297   }
298
299   // Get the value of a vector's non-struct member. Uses a named return
300   // argument to conveniently set the zero value for the result.
301   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
302                                     const FieldDef &field,
303                                     std::string *code_ptr) {
304     std::string &code = *code_ptr;
305     auto vectortype = field.value.type.VectorType();
306
307     GenReceiver(struct_def, code_ptr);
308     code += MakeCamel(NormalizedName(field));
309     code += "(self, j):";
310     code += OffsetPrefix(field);
311     code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
312     code += Indent + Indent + Indent;
313     code += "return " + GenGetter(field.value.type);
314     code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
315     code += NumToString(InlineSize(vectortype)) + "))\n";
316     if (vectortype.base_type == BASE_TYPE_STRING) {
317       code += Indent + Indent + "return \"\"\n";
318     } else {
319       code += Indent + Indent + "return 0\n";
320     }
321     code += "\n";
322   }
323
324   // Returns a non-struct vector as a numpy array. Much faster
325   // than iterating over the vector element by element.
326   void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
327                                    const FieldDef &field,
328                                    std::string *code_ptr) {
329     std::string &code = *code_ptr;
330     auto vectortype = field.value.type.VectorType();
331
332     // Currently, we only support accessing as numpy array if
333     // the vector type is a scalar.
334     if (!(IsScalar(vectortype.base_type))) { return; }
335
336     GenReceiver(struct_def, code_ptr);
337     code += MakeCamel(NormalizedName(field)) + "AsNumpy(self):";
338     code += OffsetPrefix(field);
339
340     code += Indent + Indent + Indent;
341     code += "return ";
342     code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
343     code += MakeCamel(GenTypeGet(field.value.type));
344     code += "Flags, o)\n";
345
346     if (vectortype.base_type == BASE_TYPE_STRING) {
347       code += Indent + Indent + "return \"\"\n";
348     } else {
349       code += Indent + Indent + "return 0\n";
350     }
351     code += "\n";
352   }
353
354   // Begin the creator function signature.
355   void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
356     std::string &code = *code_ptr;
357
358     code += "\n";
359     code += "def Create" + NormalizedName(struct_def);
360     code += "(builder";
361   }
362
363   // Recursively generate arguments for a constructor, to deal with nested
364   // structs.
365   void StructBuilderArgs(const StructDef &struct_def, const char *nameprefix,
366                          std::string *code_ptr) {
367     for (auto it = struct_def.fields.vec.begin();
368          it != struct_def.fields.vec.end(); ++it) {
369       auto &field = **it;
370       const auto &field_type = field.value.type;
371       const auto &type =
372           IsArray(field_type) ? field_type.VectorType() : field_type;
373       if (IsStruct(type)) {
374         // Generate arguments for a struct inside a struct. To ensure names
375         // don't clash, and to make it obvious these arguments are constructing
376         // a nested struct, prefix the name with the field name.
377         StructBuilderArgs(*field_type.struct_def,
378                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
379                           code_ptr);
380       } else {
381         std::string &code = *code_ptr;
382         code += std::string(", ") + nameprefix;
383         code += MakeCamel(NormalizedName(field), false);
384       }
385     }
386   }
387
388   // End the creator function signature.
389   void EndBuilderArgs(std::string *code_ptr) {
390     std::string &code = *code_ptr;
391     code += "):\n";
392   }
393
394   // Recursively generate struct construction statements and instert manual
395   // padding.
396   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
397                          std::string *code_ptr, size_t index = 0,
398                          bool in_array = false) {
399     std::string &code = *code_ptr;
400     std::string indent(index * 4, ' ');
401     code +=
402         indent + "    builder.Prep(" + NumToString(struct_def.minalign) + ", ";
403     code += NumToString(struct_def.bytesize) + ")\n";
404     for (auto it = struct_def.fields.vec.rbegin();
405          it != struct_def.fields.vec.rend(); ++it) {
406       auto &field = **it;
407       const auto &field_type = field.value.type;
408       const auto &type =
409           IsArray(field_type) ? field_type.VectorType() : field_type;
410       if (field.padding)
411         code +=
412             indent + "    builder.Pad(" + NumToString(field.padding) + ")\n";
413       if (IsStruct(field_type)) {
414         StructBuilderBody(*field_type.struct_def,
415                           (nameprefix + (NormalizedName(field) + "_")).c_str(),
416                           code_ptr, index, in_array);
417       } else {
418         const auto index_var = "_idx" + NumToString(index);
419         if (IsArray(field_type)) {
420           code += indent + "    for " + index_var + " in range(";
421           code += NumToString(field_type.fixed_length);
422           code += " , 0, -1):\n";
423           in_array = true;
424         }
425         if (IsStruct(type)) {
426           StructBuilderBody(
427               *field_type.struct_def,
428               (nameprefix + (NormalizedName(field) + "_")).c_str(), code_ptr,
429               index + 1, in_array);
430         } else {
431           code += IsArray(field_type) ? "    " : "";
432           code += indent + "    builder.Prepend" + GenMethod(field) + "(";
433           code += nameprefix + MakeCamel(NormalizedName(field), false);
434           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
435           for (size_t i = 0; in_array && i < array_cnt; i++) {
436             code += "[_idx" + NumToString(i) + "-1]";
437           }
438           code += ")\n";
439         }
440       }
441     }
442   }
443
444   void EndBuilderBody(std::string *code_ptr) {
445     std::string &code = *code_ptr;
446     code += "    return builder.Offset()\n";
447   }
448
449   // Get the value of a table's starting offset.
450   void GetStartOfTable(const StructDef &struct_def, std::string *code_ptr) {
451     std::string &code = *code_ptr;
452     code += "def " + NormalizedName(struct_def) + "Start";
453     code += "(builder): ";
454     code += "builder.StartObject(";
455     code += NumToString(struct_def.fields.vec.size());
456     code += ")\n";
457   }
458
459   // Set the value of a table's field.
460   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
461                          const size_t offset, std::string *code_ptr) {
462     std::string &code = *code_ptr;
463     code += "def " + NormalizedName(struct_def) + "Add" +
464             MakeCamel(NormalizedName(field));
465     code += "(builder, ";
466     code += MakeCamel(NormalizedName(field), false);
467     code += "): ";
468     code += "builder.Prepend";
469     code += GenMethod(field) + "Slot(";
470     code += NumToString(offset) + ", ";
471     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
472       code += "flatbuffers.number_types.UOffsetTFlags.py_type";
473       code += "(";
474       code += MakeCamel(NormalizedName(field), false) + ")";
475     } else {
476       code += MakeCamel(NormalizedName(field), false);
477     }
478     code += ", ";
479     code += IsFloat(field.value.type.base_type)
480                 ? float_const_gen_.GenFloatConstant(field)
481                 : field.value.constant;
482     code += ")\n";
483   }
484
485   // Set the value of one of the members of a table's vector.
486   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
487                           std::string *code_ptr) {
488     std::string &code = *code_ptr;
489     code += "def " + NormalizedName(struct_def) + "Start";
490     code += MakeCamel(NormalizedName(field));
491     code += "Vector(builder, numElems): return builder.StartVector(";
492     auto vector_type = field.value.type.VectorType();
493     auto alignment = InlineAlignment(vector_type);
494     auto elem_size = InlineSize(vector_type);
495     code += NumToString(elem_size);
496     code += ", numElems, " + NumToString(alignment);
497     code += ")\n";
498   }
499
500   // Get the offset of the end of a table.
501   void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
502     std::string &code = *code_ptr;
503     code += "def " + NormalizedName(struct_def) + "End";
504     code += "(builder): ";
505     code += "return builder.EndObject()\n";
506   }
507
508   // Generate the receiver for function signatures.
509   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) {
510     std::string &code = *code_ptr;
511     code += Indent + "# " + NormalizedName(struct_def) + "\n";
512     code += Indent + "def ";
513   }
514
515   // Generate a struct field, conditioned on its child type(s).
516   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
517                          std::string *code_ptr) {
518     GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
519     if (IsScalar(field.value.type.base_type)) {
520       if (struct_def.fixed) {
521         GetScalarFieldOfStruct(struct_def, field, code_ptr);
522       } else {
523         GetScalarFieldOfTable(struct_def, field, code_ptr);
524       }
525     } else if (IsArray(field.value.type)) {
526       GetArrayOfStruct(struct_def, field, code_ptr);
527     } else {
528       switch (field.value.type.base_type) {
529         case BASE_TYPE_STRUCT:
530           if (struct_def.fixed) {
531             GetStructFieldOfStruct(struct_def, field, code_ptr);
532           } else {
533             GetStructFieldOfTable(struct_def, field, code_ptr);
534           }
535           break;
536         case BASE_TYPE_STRING:
537           GetStringField(struct_def, field, code_ptr);
538           break;
539         case BASE_TYPE_VECTOR: {
540           auto vectortype = field.value.type.VectorType();
541           if (vectortype.base_type == BASE_TYPE_STRUCT) {
542             GetMemberOfVectorOfStruct(struct_def, field, code_ptr);
543           } else {
544             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
545             GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
546           }
547           break;
548         }
549         case BASE_TYPE_UNION: GetUnionField(struct_def, field, code_ptr); break;
550         default: FLATBUFFERS_ASSERT(0);
551       }
552     }
553     if (field.value.type.base_type == BASE_TYPE_VECTOR) {
554       GetVectorLen(struct_def, field, code_ptr);
555     }
556   }
557
558   // Generate table constructors, conditioned on its members' types.
559   void GenTableBuilders(const StructDef &struct_def, std::string *code_ptr) {
560     GetStartOfTable(struct_def, code_ptr);
561
562     for (auto it = struct_def.fields.vec.begin();
563          it != struct_def.fields.vec.end(); ++it) {
564       auto &field = **it;
565       if (field.deprecated) continue;
566
567       auto offset = it - struct_def.fields.vec.begin();
568       BuildFieldOfTable(struct_def, field, offset, code_ptr);
569       if (field.value.type.base_type == BASE_TYPE_VECTOR) {
570         BuildVectorOfTable(struct_def, field, code_ptr);
571       }
572     }
573
574     GetEndOffsetOnTable(struct_def, code_ptr);
575   }
576
577   // Generate function to check for proper file identifier
578   void GenHasFileIdentifier(const StructDef &struct_def,
579                             std::string *code_ptr) {
580     std::string &code = *code_ptr;
581     std::string escapedID;
582     // In the event any of file_identifier characters are special(NULL, \, etc),
583     // problems occur. To prevent this, convert all chars to their hex-escaped
584     // equivalent.
585     for (auto it = parser_.file_identifier_.begin();
586          it != parser_.file_identifier_.end(); ++it) {
587       escapedID += "\\x" + IntToStringHex(*it, 2);
588     }
589
590     code += Indent + "@classmethod\n";
591     code += Indent + "def " + NormalizedName(struct_def);
592     code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
593     code += "\n";
594     code += Indent + Indent;
595     code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
596     code += escapedID;
597     code += "\", size_prefixed=size_prefixed)\n";
598     code += "\n";
599   }
600
601   // Generate struct or table methods.
602   void GenStruct(const StructDef &struct_def, std::string *code_ptr) {
603     if (struct_def.generated) return;
604
605     GenComment(struct_def.doc_comment, code_ptr, &def_comment);
606     BeginClass(struct_def, code_ptr);
607     if (!struct_def.fixed) {
608       // Generate a special accessor for the table that has been declared as
609       // the root type.
610       NewRootTypeFromBuffer(struct_def, code_ptr);
611       if (parser_.file_identifier_.length()) {
612         // Generate a special function to test file_identifier
613         GenHasFileIdentifier(struct_def, code_ptr);
614       }
615     }
616     // Generate the Init method that sets the field in a pre-existing
617     // accessor object. This is to allow object reuse.
618     InitializeExisting(struct_def, code_ptr);
619     for (auto it = struct_def.fields.vec.begin();
620          it != struct_def.fields.vec.end(); ++it) {
621       auto &field = **it;
622       if (field.deprecated) continue;
623
624       GenStructAccessor(struct_def, field, code_ptr);
625     }
626
627     if (struct_def.fixed) {
628       // create a struct constructor function
629       GenStructBuilder(struct_def, code_ptr);
630     } else {
631       // Create a set of functions that allow table construction.
632       GenTableBuilders(struct_def, code_ptr);
633     }
634   }
635
636   // Generate enum declarations.
637   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) {
638     if (enum_def.generated) return;
639
640     GenComment(enum_def.doc_comment, code_ptr, &def_comment);
641     BeginEnum(NormalizedName(enum_def), code_ptr);
642     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
643       auto &ev = **it;
644       GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
645       EnumMember(enum_def, ev, code_ptr);
646     }
647     EndEnum(code_ptr);
648   }
649
650   // Returns the function name that is able to read a value of the given type.
651   std::string GenGetter(const Type &type) {
652     switch (type.base_type) {
653       case BASE_TYPE_STRING: return "self._tab.String(";
654       case BASE_TYPE_UNION: return "self._tab.Union(";
655       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
656       default:
657         return "self._tab.Get(flatbuffers.number_types." +
658                MakeCamel(GenTypeGet(type)) + "Flags, ";
659     }
660   }
661
662   // Returns the method name for use with add/put calls.
663   std::string GenMethod(const FieldDef &field) {
664     return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
665                ? MakeCamel(GenTypeBasic(field.value.type))
666                : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
667   }
668
669   std::string GenTypeBasic(const Type &type) {
670     static const char *ctypename[] = {
671     // clang-format off
672       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
673         CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, RTYPE, KTYPE) \
674         #PTYPE,
675         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
676       #undef FLATBUFFERS_TD
677       // clang-format on
678     };
679     return ctypename[IsArray(type) ? type.VectorType().base_type
680                                    : type.base_type];
681   }
682
683   std::string GenTypePointer(const Type &type) {
684     switch (type.base_type) {
685       case BASE_TYPE_STRING: return "string";
686       case BASE_TYPE_VECTOR: return GenTypeGet(type.VectorType());
687       case BASE_TYPE_STRUCT: return type.struct_def->name;
688       case BASE_TYPE_UNION:
689         // fall through
690       default: return "*flatbuffers.Table";
691     }
692   }
693
694   std::string GenTypeGet(const Type &type) {
695     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
696   }
697
698   std::string TypeName(const FieldDef &field) {
699     return GenTypeGet(field.value.type);
700   }
701
702   // Create a struct with a builder and the struct's arguments.
703   void GenStructBuilder(const StructDef &struct_def, std::string *code_ptr) {
704     BeginBuilderArgs(struct_def, code_ptr);
705     StructBuilderArgs(struct_def, "", code_ptr);
706     EndBuilderArgs(code_ptr);
707
708     StructBuilderBody(struct_def, "", code_ptr);
709     EndBuilderBody(code_ptr);
710   }
711
712   bool generate() {
713     if (!generateEnums()) return false;
714     if (!generateStructs()) return false;
715     return true;
716   }
717
718  private:
719   bool generateEnums() {
720     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
721          ++it) {
722       auto &enum_def = **it;
723       std::string enumcode;
724       GenEnum(enum_def, &enumcode);
725       if (!SaveType(enum_def, enumcode, false)) return false;
726     }
727     return true;
728   }
729
730   bool generateStructs() {
731     for (auto it = parser_.structs_.vec.begin();
732          it != parser_.structs_.vec.end(); ++it) {
733       auto &struct_def = **it;
734       std::string declcode;
735       GenStruct(struct_def, &declcode);
736       if (!SaveType(struct_def, declcode, true)) return false;
737     }
738     return true;
739   }
740
741   // Begin by declaring namespace and imports.
742   void BeginFile(const std::string &name_space_name, const bool needs_imports,
743                  std::string *code_ptr) {
744     std::string &code = *code_ptr;
745     code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
746     code += "# namespace: " + name_space_name + "\n\n";
747     if (needs_imports) { code += "import flatbuffers\n\n"; }
748   }
749
750   // Save out the generated code for a Python Table type.
751   bool SaveType(const Definition &def, const std::string &classcode,
752                 bool needs_imports) {
753     if (!classcode.length()) return true;
754
755     std::string namespace_dir = path_;
756     auto &namespaces = def.defined_namespace->components;
757     for (auto it = namespaces.begin(); it != namespaces.end(); ++it) {
758       if (it != namespaces.begin()) namespace_dir += kPathSeparator;
759       namespace_dir += *it;
760       std::string init_py_filename = namespace_dir + "/__init__.py";
761       SaveFile(init_py_filename.c_str(), "", false);
762     }
763
764     std::string code = "";
765     BeginFile(LastNamespacePart(*def.defined_namespace), needs_imports, &code);
766     code += classcode;
767     std::string filename =
768         NamespaceDir(*def.defined_namespace) + NormalizedName(def) + ".py";
769     return SaveFile(filename.c_str(), code, false);
770   }
771
772  private:
773   std::unordered_set<std::string> keywords_;
774   const SimpleFloatConstantGenerator float_const_gen_;
775 };
776
777 }  // namespace python
778
779 bool GeneratePython(const Parser &parser, const std::string &path,
780                     const std::string &file_name) {
781   python::PythonGenerator generator(parser, path, file_name);
782   return generator.generate();
783 }
784
785 }  // namespace flatbuffers