• 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 "idl_gen_python.h"
20 
21 #include <algorithm>
22 #include <cstddef>
23 #include <cstdint>
24 #include <cstdio>
25 #include <map>
26 #include <set>
27 #include <sstream>
28 #include <string>
29 #include <utility>
30 #include <vector>
31 
32 #include "codegen/idl_namer.h"
33 #include "codegen/python.h"
34 #include "flatbuffers/code_generators.h"
35 #include "flatbuffers/flatbuffers.h"
36 #include "flatbuffers/idl.h"
37 #include "flatbuffers/util.h"
38 
39 namespace flatbuffers {
40 namespace python {
41 
42 namespace {
43 
44 typedef std::pair<std::string, std::string> ImportMapEntry;
45 typedef std::set<ImportMapEntry> ImportMap;
46 
47 // Hardcode spaces per indentation.
48 static const CommentConfig def_comment = { nullptr, "#", nullptr };
49 static const std::string Indent = "    ";
50 
51 class PythonStubGenerator {
52  public:
PythonStubGenerator(const Parser & parser,const std::string & path,const Version & version)53   PythonStubGenerator(const Parser &parser, const std::string &path,
54                       const Version &version)
55       : parser_{parser},
56         namer_{WithFlagOptions(kStubConfig, parser.opts, path),
57                Keywords(version)},
58         version_(version) {}
59 
Generate()60   bool Generate() {
61     if (parser_.opts.one_file) {
62       Imports imports;
63       std::stringstream stub;
64 
65       DeclareUOffset(stub, &imports);
66       for (const EnumDef *def : parser_.enums_.vec) {
67         if (def->generated) continue;
68         GenerateEnumStub(stub, def, &imports);
69       }
70       for (const StructDef *def : parser_.structs_.vec) {
71         if (def->generated) continue;
72         GenerateStructStub(stub, def, &imports);
73       }
74 
75       std::string filename =
76           namer_.config_.output_path +
77           StripPath(StripExtension(parser_.file_being_parsed_)) +
78           namer_.config_.filename_suffix + namer_.config_.filename_extension;
79 
80       return SaveFile(filename, imports, stub);
81     }
82 
83     for (const EnumDef *def : parser_.enums_.vec) {
84       if (def->generated) continue;
85 
86       Imports imports;
87       std::stringstream stub;
88 
89       DeclareUOffset(stub, &imports);
90       GenerateEnumStub(stub, def, &imports);
91 
92       std::string filename = namer_.Directories(*def->defined_namespace) +
93                              namer_.File(*def, SkipFile::Suffix);
94       if (!SaveFile(filename, imports, stub)) return false;
95     }
96 
97     for (const StructDef *def : parser_.structs_.vec) {
98       if (def->generated) continue;
99 
100       Imports imports;
101       std::stringstream stub;
102 
103       DeclareUOffset(stub, &imports);
104       GenerateStructStub(stub, def, &imports);
105 
106       std::string filename = namer_.Directories(*def->defined_namespace) +
107                              namer_.File(*def, SkipFile::Suffix);
108       if (!SaveFile(filename, imports, stub)) return false;
109     }
110 
111     return true;
112   }
113 
114  private:
SaveFile(const std::string & filename,const Imports & imports,const std::stringstream & content)115   bool SaveFile(const std::string &filename, const Imports &imports,
116                 const std::stringstream &content) {
117     std::stringstream ss;
118     GenerateImports(ss, imports);
119     ss << '\n';
120     ss << content.str() << '\n';
121 
122     EnsureDirExists(StripFileName(filename));
123     return flatbuffers::SaveFile(filename.c_str(), ss.str(), false);
124   }
125 
DeclareUOffset(std::stringstream & stub,Imports * imports)126   static void DeclareUOffset(std::stringstream &stub, Imports *imports) {
127     imports->Import("flatbuffers");
128     imports->Import("typing");
129     stub << "uoffset: typing.TypeAlias = "
130             "flatbuffers.number_types.UOffsetTFlags.py_type\n"
131          << '\n';
132   }
133 
ModuleForFile(const std::string & file) const134   std::string ModuleForFile(const std::string &file) const {
135     if (parser_.file_being_parsed_ == file) return ".";
136 
137     std::string module = parser_.opts.include_prefix + StripExtension(file) +
138                          parser_.opts.filename_suffix;
139     std::replace(module.begin(), module.end(), '/', '.');
140     return module;
141   }
142 
143   template <typename T>
ModuleFor(const T * def) const144   std::string ModuleFor(const T *def) const {
145     if (parser_.opts.one_file) return ModuleForFile(def->file);
146     return namer_.NamespacedType(*def);
147   }
148 
GetNestedStruct(const FieldDef * field) const149   const StructDef *GetNestedStruct(const FieldDef *field) const {
150     const Value *nested = field->attributes.Lookup("nested_flatbuffer");
151     if (nested == nullptr) return nullptr;
152 
153     StructDef *nested_def = parser_.LookupStruct(nested->constant);
154     if (nested_def != nullptr) return nested_def;
155 
156     return parser_.LookupStruct(namer_.NamespacedType(
157         parser_.current_namespace_->components, nested->constant));
158   }
159 
ScalarType(BaseType type)160   static std::string ScalarType(BaseType type) {
161     if (IsBool(type)) return "bool";
162     if (IsInteger(type)) return "int";
163     if (IsFloat(type)) return "float";
164     FLATBUFFERS_ASSERT(false);
165     return "None";
166   }
167 
168   template <typename F>
UnionType(const EnumDef & enum_def,Imports * imports,F type) const169   std::string UnionType(const EnumDef &enum_def, Imports *imports,
170                         F type) const {
171     imports->Import("typing");
172 
173     std::string result = "";
174     for (const EnumVal *val : enum_def.Vals()) {
175       if (!result.empty()) result += ", ";
176 
177       switch (val->union_type.base_type) {
178         case BASE_TYPE_STRUCT: {
179           Import import = imports->Import(ModuleFor(val->union_type.struct_def),
180                                           type(*val->union_type.struct_def));
181           result += import.name;
182           break;
183         }
184         case BASE_TYPE_STRING:
185           result += "str";
186           break;
187         case BASE_TYPE_NONE:
188           result += "None";
189           break;
190         default:
191           break;
192       }
193     }
194     return "typing.Union[" + result + "]";
195   }
196 
UnionObjectType(const EnumDef & enum_def,Imports * imports) const197   std::string UnionObjectType(const EnumDef &enum_def, Imports *imports) const {
198     return UnionType(enum_def, imports, [this](const StructDef &struct_def) {
199       return namer_.ObjectType(struct_def);
200     });
201   }
202 
UnionType(const EnumDef & enum_def,Imports * imports) const203   std::string UnionType(const EnumDef &enum_def, Imports *imports) const {
204     return UnionType(enum_def, imports, [this](const StructDef &struct_def) {
205       return namer_.Type(struct_def);
206     });
207   }
208 
EnumType(const EnumDef & enum_def,Imports * imports) const209   std::string EnumType(const EnumDef &enum_def, Imports *imports) const {
210     imports->Import("typing");
211     const Import &import =
212         imports->Import(ModuleFor(&enum_def), namer_.Type(enum_def));
213 
214     std::string result = "";
215     for (const EnumVal *val : enum_def.Vals()) {
216       if (!result.empty()) result += ", ";
217       result += import.name + "." + namer_.Variant(*val);
218     }
219     return "typing.Literal[" + result + "]";
220   }
221 
TypeOf(const Type & type,Imports * imports) const222   std::string TypeOf(const Type &type, Imports *imports) const {
223     if (type.enum_def != nullptr) return EnumType(*type.enum_def, imports);
224     if (IsScalar(type.base_type)) return ScalarType(type.base_type);
225 
226     switch (type.base_type) {
227       case BASE_TYPE_STRUCT: {
228         const Import &import = imports->Import(ModuleFor(type.struct_def),
229                                                namer_.Type(*type.struct_def));
230         return import.name;
231       }
232       case BASE_TYPE_STRING:
233         return "str";
234       case BASE_TYPE_ARRAY:
235       case BASE_TYPE_VECTOR: {
236         imports->Import("typing");
237         return "typing.List[" + TypeOf(type.VectorType(), imports) + "]";
238       }
239       case BASE_TYPE_UNION:
240         return UnionType(*type.enum_def, imports);
241       default:
242         FLATBUFFERS_ASSERT(0);
243         return "";
244     }
245   }
246 
GenerateObjectFieldStub(const FieldDef * field,Imports * imports) const247   std::string GenerateObjectFieldStub(const FieldDef *field,
248                                       Imports *imports) const {
249     std::string field_name = namer_.Field(*field);
250 
251     const Type &field_type = field->value.type;
252     if (IsScalar(field_type.base_type)) {
253       std::string result = field_name + ": " + TypeOf(field_type, imports);
254       if (field->IsOptional()) result += " | None";
255       return result;
256     }
257 
258     switch (field_type.base_type) {
259       case BASE_TYPE_STRUCT: {
260         Import import =
261             imports->Import(ModuleFor(field_type.struct_def),
262                             namer_.ObjectType(*field_type.struct_def));
263         return field_name + ": " + import.name + " | None";
264       }
265       case BASE_TYPE_STRING:
266         return field_name + ": str | None";
267       case BASE_TYPE_ARRAY:
268       case BASE_TYPE_VECTOR: {
269         imports->Import("typing");
270         if (field_type.element == BASE_TYPE_STRUCT) {
271           Import import =
272               imports->Import(ModuleFor(field_type.struct_def),
273                               namer_.ObjectType(*field_type.struct_def));
274           return field_name + ": typing.List[" + import.name + "]";
275         }
276         if (field_type.element == BASE_TYPE_STRING) {
277           return field_name + ": typing.List[str]";
278         }
279         return field_name + ": typing.List[" +
280                TypeOf(field_type.VectorType(), imports) + "]";
281       }
282       case BASE_TYPE_UNION:
283         return field_name + ": " +
284                UnionObjectType(*field->value.type.enum_def, imports);
285       default:
286         return field_name;
287     }
288   }
289 
GenerateObjectStub(std::stringstream & stub,const StructDef * struct_def,Imports * imports) const290   void GenerateObjectStub(std::stringstream &stub, const StructDef *struct_def,
291                           Imports *imports) const {
292     std::string name = namer_.ObjectType(*struct_def);
293 
294     stub << "class " << name;
295     if (version_.major != 3) stub << "(object)";
296     stub << ":\n";
297     for (const FieldDef *field : struct_def->fields.vec) {
298       if (field->deprecated) continue;
299       stub << "  " << GenerateObjectFieldStub(field, imports) << "\n";
300     }
301 
302     stub << "  @classmethod\n";
303     stub << "  def InitFromBuf(cls, buf: bytes, pos: int) -> " << name
304          << ": ...\n";
305 
306     stub << "  @classmethod\n";
307     stub << "  def InitFromPackedBuf(cls, buf: bytes, pos: int = 0) -> " << name
308          << ": ...\n";
309 
310     const Import &import =
311         imports->Import(ModuleFor(struct_def), namer_.Type(*struct_def));
312 
313     stub << "  @classmethod\n";
314     stub << "  def InitFromObj(cls, " << namer_.Variable(*struct_def)
315          << ": " + import.name + ") -> " << name << ": ...\n";
316 
317     stub << "  def _UnPack(self, " << namer_.Variable(*struct_def) << ": "
318          << import.name << ") -> None: ...\n";
319 
320     stub << "  def Pack(self, builder: flatbuffers.Builder) -> None: ...\n";
321 
322     if (parser_.opts.gen_compare) {
323       stub << "  def __eq__(self, other: " << name + ") -> bool: ...\n";
324     }
325   }
326 
GenerateStructStub(std::stringstream & stub,const StructDef * struct_def,Imports * imports) const327   void GenerateStructStub(std::stringstream &stub, const StructDef *struct_def,
328                           Imports *imports) const {
329     std::string type = namer_.Type(*struct_def);
330 
331     stub << "class " << type;
332     if (version_.major != 3) stub << "(object)";
333     stub << ":\n";
334     if (struct_def->fixed) {
335       stub << "  @classmethod\n";
336       stub << "  def SizeOf(cls) -> int: ...\n\n";
337     } else {
338       stub << "  @classmethod\n";
339       stub << "  def GetRootAs(cls, buf: bytes, offset: int) -> " << type
340            << ": ...\n";
341 
342       if (!parser_.opts.python_no_type_prefix_suffix) {
343         stub << "  @classmethod\n";
344         stub << "  def GetRootAs" << type
345              << "(cls, buf: bytes, offset: int) -> " << type << ": ...\n";
346       }
347       if (parser_.file_identifier_.length()) {
348         stub << "  @classmethod\n";
349         stub << "  def " << type
350              << "BufferHasIdentifier(cls, buf: bytes, offset: int, "
351                 "size_prefixed: bool) -> bool: ...\n";
352       }
353     }
354 
355     stub << "  def Init(self, buf: bytes, pos: int) -> None: ...\n";
356 
357     for (const FieldDef *field : struct_def->fields.vec) {
358       if (field->deprecated) continue;
359 
360       std::string name = namer_.Method(*field);
361 
362       const Type &field_type = field->value.type;
363       if (IsScalar(field_type.base_type)) {
364         stub << "  def " << name << "(self) -> " << TypeOf(field_type, imports);
365         if (field->IsOptional()) stub << " | None";
366         stub << ": ...\n";
367       } else {
368         switch (field_type.base_type) {
369           case BASE_TYPE_STRUCT: {
370             const Import &import =
371                 imports->Import(ModuleFor(field_type.struct_def),
372                                 namer_.Type(*field_type.struct_def));
373             if (struct_def->fixed) {
374               stub << "  def " << name << "(self, obj: " << import.name
375                    << ") -> " << import.name << ": ...\n";
376             } else {
377               stub << "  def " << name + "(self) -> " << import.name
378                    << " | None: ...\n";
379             }
380             break;
381           }
382           case BASE_TYPE_STRING:
383             stub << "  def " << name << "(self) -> str | None: ...\n";
384             break;
385           case BASE_TYPE_ARRAY:
386           case BASE_TYPE_VECTOR: {
387             switch (field_type.element) {
388               case BASE_TYPE_STRUCT: {
389                 const Import &import =
390                     imports->Import(ModuleFor(field_type.struct_def),
391                                     namer_.Type(*field_type.struct_def));
392                 stub << "  def " << name << "(self, i: int) -> " << import.name
393                      << " | None: ...\n";
394                 break;
395               }
396               case BASE_TYPE_STRING:
397                 stub << "  def " << name << "(self, i: int) -> str: ...\n";
398                 break;
399               default:  // scalars
400                 stub << "  def " << name << "(self, i: int) -> "
401                      << TypeOf(field_type, imports) << ": ...\n";
402 
403                 if (parser_.opts.python_gen_numpy) {
404                   stub << "  def " << name
405                        << "AsNumpy(self) -> np.ndarray: ...\n";
406                 }
407 
408                 const StructDef *nested_def = GetNestedStruct(field);
409                 if (nested_def != nullptr) {
410                   const Import &import = imports->Import(
411                       ModuleFor(nested_def), namer_.Type(*nested_def));
412 
413                   stub << "  def " << name + "NestedRoot(self) -> "
414                        << import.name << " | None: ...\n";
415                 }
416                 break;
417             }
418             stub << "  def " << name << "Length(self) -> int: ...\n";
419             stub << "  def " << name << "IsNone(self) -> bool: ...\n";
420             break;
421           }
422           case BASE_TYPE_UNION: {
423             imports->Import("flatbuffers", "table");
424             stub << "  def " << name << "(self) -> table.Table | None: ...\n";
425             break;
426           }
427           default:
428             break;
429         }
430       }
431     }
432 
433     if (parser_.opts.generate_object_based_api) {
434       GenerateObjectStub(stub, struct_def, imports);
435     }
436 
437     if (struct_def->fixed) {
438       GenerateStructBuilderStub(stub, struct_def, imports);
439     } else {
440       GenerateTableBuilderStub(stub, struct_def, imports);
441     }
442   }
443 
StructBuilderArgs(const StructDef & struct_def,const std::string prefix,Imports * imports,std::vector<std::string> * args) const444   void StructBuilderArgs(const StructDef &struct_def, const std::string prefix,
445                          Imports *imports,
446                          std::vector<std::string> *args) const {
447     for (const FieldDef *field : struct_def.fields.vec) {
448       const Type type = IsArray(field->value.type)
449                             ? field->value.type.VectorType()
450                             : field->value.type;
451       if (type.base_type == BASE_TYPE_STRUCT) {
452         StructBuilderArgs(*field->value.type.struct_def,
453                           prefix + namer_.Field(*field) + "_", imports, args);
454       } else {
455         args->push_back(prefix + namer_.Field(*field) + ": " +
456                         TypeOf(type, imports));
457       }
458     }
459   }
460 
GenerateStructBuilderStub(std::stringstream & stub,const StructDef * struct_def,Imports * imports) const461   void GenerateStructBuilderStub(std::stringstream &stub,
462                                  const StructDef *struct_def,
463                                  Imports *imports) const {
464     imports->Import("flatbuffers");
465 
466     std::vector<std::string> args;
467     StructBuilderArgs(*struct_def, "", imports, &args);
468 
469     stub << '\n';
470     stub << "def Create" + namer_.Type(*struct_def)
471          << "(builder: flatbuffers.Builder";
472     for (const std::string &arg : args) {
473       stub << ", " << arg;
474     }
475     stub << ") -> uoffset: ...\n";
476   }
477 
GenerateTableBuilderStub(std::stringstream & stub,const StructDef * struct_def,Imports * imports) const478   void GenerateTableBuilderStub(std::stringstream &stub,
479                                 const StructDef *struct_def,
480                                 Imports *imports) const {
481     std::string type = namer_.Type(*struct_def);
482 
483     /**************************** def TableStart ****************************/
484     stub << "def ";
485     if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
486     stub << "Start(builder: flatbuffers.Builder) -> None: ...\n";
487     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
488       stub << "def Start(builder: flatbuffers.Builder) -> None: ...\n";
489     }
490 
491     /************************** def TableAddField ***************************/
492     for (const FieldDef *field : struct_def->fields.vec) {
493       if (field->deprecated) continue;
494 
495       stub << "def ";
496       if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
497       stub << "Add" << namer_.Method(*field)
498            << "(builder: flatbuffers.Builder, "
499            << namer_.Variable(*field) + ": ";
500       if (IsScalar(field->value.type.base_type)) {
501         stub << TypeOf(field->value.type, imports);
502       } else if (IsArray(field->value.type)) {
503         stub << TypeOf(field->value.type.VectorType(), imports);
504       } else {
505         stub << "uoffset";
506       }
507       stub << ") -> None: ...\n";
508 
509       if (IsVector(field->value.type)) {
510         stub << "def ";
511         if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
512         stub << "Start" << namer_.Method(*field)
513              << "Vector(builder: flatbuffers.Builder, num_elems: int) -> "
514                 "uoffset: ...\n";
515 
516         if (!parser_.opts.one_file &&
517             !parser_.opts.python_no_type_prefix_suffix) {
518           stub << "def Start" << namer_.Method(*field)
519                << "Vector(builder: flatbuffers.Builder, num_elems: int) -> "
520                   "uoffset: ...\n";
521         }
522 
523         if (GetNestedStruct(field) != nullptr) {
524           stub << "def " << type << "Make" << namer_.Method(*field)
525                << "VectorFromBytes(builder: flatbuffers.Builder, buf: "
526                   "bytes) -> uoffset: ...\n";
527           if (!parser_.opts.one_file) {
528             stub << "def Make" << namer_.Method(*field)
529                  << "VectorFromBytes(builder: flatbuffers.Builder, buf: "
530                     "bytes) -> uoffset: ...\n";
531           }
532         }
533       }
534     }
535 
536     /***************************** def TableEnd *****************************/
537     stub << "def ";
538     if (!parser_.opts.python_no_type_prefix_suffix) stub << type;
539     stub << "End(builder: flatbuffers.Builder) -> uoffset: ...\n";
540     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
541       stub << "def End(builder: flatbuffers.Builder) -> uoffset: ...\n";
542     }
543   }
544 
GenerateEnumStub(std::stringstream & stub,const EnumDef * enum_def,Imports * imports) const545   void GenerateEnumStub(std::stringstream &stub, const EnumDef *enum_def,
546                         Imports *imports) const {
547     stub << "class " << namer_.Type(*enum_def);
548 
549     if (version_.major == 3){
550       imports->Import("enum", "IntEnum");
551       stub << "(IntEnum)";
552     }
553     else {
554       stub << "(object)";
555     }
556 
557     stub << ":\n";
558     for (const EnumVal *val : enum_def->Vals()) {
559       stub << "  " << namer_.Variant(*val) << ": "
560            << ScalarType(enum_def->underlying_type.base_type) << "\n";
561     }
562 
563     if (parser_.opts.generate_object_based_api & enum_def->is_union) {
564       imports->Import("flatbuffers", "table");
565       stub << "def " << namer_.Function(*enum_def)
566            << "Creator(union_type: " << EnumType(*enum_def, imports)
567            << ", table: table.Table) -> " << UnionType(*enum_def, imports)
568            << ": ...\n";
569     }
570   }
571 
GenerateImports(std::stringstream & ss,const Imports & imports)572   void GenerateImports(std::stringstream &ss, const Imports &imports) {
573     ss << "from __future__ import annotations\n";
574     ss << '\n';
575     ss << "import flatbuffers\n";
576     if (parser_.opts.python_gen_numpy) {
577       ss << "import numpy as np\n";
578     }
579     ss << '\n';
580 
581     std::set<std::string> modules;
582     std::map<std::string, std::set<std::string>> names_by_module;
583     for (const Import &import : imports.imports) {
584       if (import.IsLocal()) continue;  // skip all local imports
585       if (import.name == "") {
586         modules.insert(import.module);
587       } else {
588         names_by_module[import.module].insert(import.name);
589       }
590     }
591 
592     for (const std::string &module : modules) {
593       ss << "import " << module << '\n';
594     }
595     for (const auto &import : names_by_module) {
596       ss << "from " << import.first << " import ";
597       size_t i = 0;
598       for (const std::string &name : import.second) {
599         if (i > 0) ss << ", ";
600         ss << name;
601         ++i;
602       }
603       ss << '\n';
604     }
605   }
606 
607   const Parser &parser_;
608   const IdlNamer namer_;
609   const Version version_;
610 };}  // namespace
611 
612 class PythonGenerator : public BaseGenerator {
613  public:
PythonGenerator(const Parser & parser,const std::string & path,const std::string & file_name,const Version & version)614   PythonGenerator(const Parser &parser, const std::string &path,
615                   const std::string &file_name, const Version &version)
616       : BaseGenerator(parser, path, file_name, "" /* not used */,
617                       "" /* not used */, "py"),
618         float_const_gen_("float('nan')", "float('inf')", "float('-inf')"),
619         namer_(WithFlagOptions(kConfig, parser.opts, path),
620                Keywords(version)) {}
621 
622   // Most field accessors need to retrieve and test the field offset first,
623   // this is the prefix code for that.
OffsetPrefix(const FieldDef & field,bool new_line=true) const624   std::string OffsetPrefix(const FieldDef &field, bool new_line = true) const {
625     return "\n" + Indent + Indent +
626            "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
627            "(self._tab.Offset(" + NumToString(field.value.offset) + "))\n" +
628            Indent + Indent + "if o != 0:" + (new_line ? "\n" : "");
629   }
630 
631   // Begin a class declaration.
BeginClass(const StructDef & struct_def,std::string * code_ptr) const632   void BeginClass(const StructDef &struct_def, std::string *code_ptr) const {
633     auto &code = *code_ptr;
634     code += "class " + namer_.Type(struct_def) + "(object):\n";
635     code += Indent + "__slots__ = ['_tab']";
636     code += "\n\n";
637   }
638 
639   // Begin enum code with a class declaration.
BeginEnum(const EnumDef & enum_def,std::string * code_ptr) const640   void BeginEnum(const EnumDef &enum_def, std::string *code_ptr) const {
641     auto &code = *code_ptr;
642     code += "class " + namer_.Type(enum_def) + "(object):\n";
643   }
644 
645   // Starts a new line and then indents.
GenIndents(int num) const646   std::string GenIndents(int num) const {
647     return "\n" + std::string(num * Indent.length(), ' ');
648   }
649 
650   // A single enum member.
EnumMember(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr) const651   void EnumMember(const EnumDef &enum_def, const EnumVal &ev,
652                   std::string *code_ptr) const {
653     auto &code = *code_ptr;
654     code += Indent;
655     code += namer_.Variant(ev);
656     code += " = ";
657     code += enum_def.ToString(ev) + "\n";
658   }
659 
660   // Initialize a new struct or table from existing data.
NewRootTypeFromBuffer(const StructDef & struct_def,std::string * code_ptr) const661   void NewRootTypeFromBuffer(const StructDef &struct_def,
662                              std::string *code_ptr) const {
663     auto &code = *code_ptr;
664     const std::string struct_type = namer_.Type(struct_def);
665 
666     code += Indent + "@classmethod\n";
667     code += Indent + "def GetRootAs";
668     if (parser_.opts.python_typing) {
669       code += "(cls, buf, offset: int = 0):";
670     } else {
671       code += "(cls, buf, offset=0):";
672     }
673     code += "\n";
674     code += Indent + Indent;
675     code += "n = flatbuffers.encode.Get";
676     code += "(flatbuffers.packer.uoffset, buf, offset)\n";
677     code += Indent + Indent + "x = " + struct_type + "()\n";
678     code += Indent + Indent + "x.Init(buf, n + offset)\n";
679     code += Indent + Indent + "return x\n";
680     code += "\n";
681 
682     if (!parser_.opts.python_no_type_prefix_suffix) {
683       // Add an alias with the old name
684       code += Indent + "@classmethod\n";
685       code +=
686           Indent + "def GetRootAs" + struct_type + "(cls, buf, offset=0):\n";
687       code += Indent + Indent +
688               "\"\"\"This method is deprecated. Please switch to "
689               "GetRootAs.\"\"\"\n";
690       code += Indent + Indent + "return cls.GetRootAs(buf, offset)\n";
691     }
692   }
693 
694   // Initialize an existing object with other data, to avoid an allocation.
InitializeExisting(const StructDef & struct_def,std::string * code_ptr) const695   void InitializeExisting(const StructDef &struct_def,
696                           std::string *code_ptr) const {
697     auto &code = *code_ptr;
698 
699     GenReceiver(struct_def, code_ptr);
700     if (parser_.opts.python_typing) {
701       code += "Init(self, buf: bytes, pos: int):\n";
702     } else {
703       code += "Init(self, buf, pos):\n";
704     }
705     code += Indent + Indent + "self._tab = flatbuffers.table.Table(buf, pos)\n";
706     code += "\n";
707   }
708 
709   // Get the length of a vector.
GetVectorLen(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const710   void GetVectorLen(const StructDef &struct_def, const FieldDef &field,
711                     std::string *code_ptr) const {
712     auto &code = *code_ptr;
713 
714     GenReceiver(struct_def, code_ptr);
715     code += namer_.Method(field) + "Length(self)";
716     if (parser_.opts.python_typing) { code += " -> int"; }
717     code += ":";
718     if (!IsArray(field.value.type)) {
719       code += OffsetPrefix(field, false);
720       code += GenIndents(3) + "return self._tab.VectorLen(o)";
721       code += GenIndents(2) + "return 0\n\n";
722     } else {
723       code += GenIndents(2) + "return " +
724               NumToString(field.value.type.fixed_length) + "\n\n";
725     }
726   }
727 
728   // Determines whether a vector is none or not.
GetVectorIsNone(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const729   void GetVectorIsNone(const StructDef &struct_def, const FieldDef &field,
730                        std::string *code_ptr) const {
731     auto &code = *code_ptr;
732 
733     GenReceiver(struct_def, code_ptr);
734     code += namer_.Method(field) + "IsNone(self)";
735     if (parser_.opts.python_typing) { code += " -> bool"; }
736     code += ":";
737     if (!IsArray(field.value.type)) {
738       code += GenIndents(2) +
739               "o = flatbuffers.number_types.UOffsetTFlags.py_type" +
740               "(self._tab.Offset(" + NumToString(field.value.offset) + "))";
741       code += GenIndents(2) + "return o == 0";
742     } else {
743       // assume that we always have an array as memory is preassigned
744       code += GenIndents(2) + "return False";
745     }
746     code += "\n\n";
747   }
748 
749   // Get the value of a struct's scalar.
GetScalarFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const750   void GetScalarFieldOfStruct(const StructDef &struct_def,
751                               const FieldDef &field,
752                               std::string *code_ptr) const {
753     auto &code = *code_ptr;
754     std::string getter = GenGetter(field.value.type);
755     GenReceiver(struct_def, code_ptr);
756     code += namer_.Method(field);
757     code += "(self): return " + getter;
758     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
759     code += NumToString(field.value.offset) + "))\n";
760   }
761 
762   // Get the value of a table's scalar.
GetScalarFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const763   void GetScalarFieldOfTable(const StructDef &struct_def, const FieldDef &field,
764                              std::string *code_ptr) const {
765     auto &code = *code_ptr;
766     std::string getter = GenGetter(field.value.type);
767     GenReceiver(struct_def, code_ptr);
768     code += namer_.Method(field);
769     code += "(self):";
770     code += OffsetPrefix(field);
771     getter += "o + self._tab.Pos)";
772     auto is_bool = IsBool(field.value.type.base_type);
773     if (is_bool) { getter = "bool(" + getter + ")"; }
774     code += Indent + Indent + Indent + "return " + getter + "\n";
775     std::string default_value;
776     if (field.IsScalarOptional()) {
777       default_value = "None";
778     } else if (is_bool) {
779       default_value = field.value.constant == "0" ? "False" : "True";
780     } else {
781       default_value = IsFloat(field.value.type.base_type)
782                           ? float_const_gen_.GenFloatConstant(field)
783                           : field.value.constant;
784     }
785     code += Indent + Indent + "return " + default_value + "\n\n";
786   }
787 
788   // Get a struct by initializing an existing struct.
789   // Specific to Struct.
GetStructFieldOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const790   void GetStructFieldOfStruct(const StructDef &struct_def,
791                               const FieldDef &field,
792                               std::string *code_ptr) const {
793     auto &code = *code_ptr;
794     GenReceiver(struct_def, code_ptr);
795     code += namer_.Method(field);
796     code += "(self, obj):\n";
797     code += Indent + Indent + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
798     code += NumToString(field.value.offset) + ")";
799     code += "\n" + Indent + Indent + "return obj\n\n";
800   }
801 
802   // Get the value of a fixed size array.
GetArrayOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const803   void GetArrayOfStruct(const StructDef &struct_def, const FieldDef &field,
804                         std::string *code_ptr, ImportMap &imports) const {
805     auto &code = *code_ptr;
806     const auto vec_type = field.value.type.VectorType();
807     GenReceiver(struct_def, code_ptr);
808     code += namer_.Method(field);
809 
810     const ImportMapEntry import_entry = {
811       GenPackageReference(field.value.type), TypeName(field)
812     };
813 
814     if (parser_.opts.python_typing) {
815       const std::string return_type = ReturnType(struct_def, field);
816       code += "(self, i: int)";
817       code += " -> " + return_type + ":";
818 
819       imports.insert(import_entry);
820     } else {
821       code += "(self, i):";
822     }
823 
824     if (parser_.opts.include_dependence_headers &&
825         !parser_.opts.python_typing) {
826       code += GenIndents(2);
827       code += "from " + import_entry.first + " import " + import_entry.second +
828               "\n";
829     }
830 
831     code += GenIndents(2) + "obj = " + TypeName(field) + "()";
832     code += GenIndents(2) + "obj.Init(self._tab.Bytes, self._tab.Pos + ";
833     code += NumToString(field.value.offset) + " + i * ";
834     code += NumToString(InlineSize(vec_type));
835     code += ")" + GenIndents(2) + "return obj\n\n";
836   }
837 
838   // Get the value of a vector's non-struct member. Uses a named return
839   // argument to conveniently set the zero value for the result.
GetArrayOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const840   void GetArrayOfNonStruct(const StructDef &struct_def, const FieldDef &field,
841                            std::string *code_ptr) const {
842     auto &code = *code_ptr;
843     GenReceiver(struct_def, code_ptr);
844     code += namer_.Method(field);
845     code += "(self, j = None):";
846     code += GenIndents(2) + "if j is None:";
847     code += GenIndents(3) + "return [" + GenGetter(field.value.type);
848     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
849     code += NumToString(field.value.offset) + " + i * ";
850     code += NumToString(InlineSize(field.value.type.VectorType()));
851     code += ")) for i in range(";
852     code += "self." + namer_.Method(field) + "Length()" + ")]";
853     code += GenIndents(2) + "elif j >= 0 and j < self." + namer_.Method(field) +
854             "Length():";
855     code += GenIndents(3) + "return " + GenGetter(field.value.type);
856     code += "self._tab.Pos + flatbuffers.number_types.UOffsetTFlags.py_type(";
857     code += NumToString(field.value.offset) + " + j * ";
858     code += NumToString(InlineSize(field.value.type.VectorType()));
859     code += "))";
860     code += GenIndents(2) + "else:";
861     code += GenIndents(3) + "return None\n\n";
862   }
863 
864   // Get a struct by initializing an existing struct.
865   // Specific to Table.
GetStructFieldOfTable(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const866   void GetStructFieldOfTable(const StructDef &struct_def, const FieldDef &field,
867                              std::string *code_ptr, ImportMap &imports) const {
868     auto &code = *code_ptr;
869     GenReceiver(struct_def, code_ptr);
870     code += namer_.Method(field) + "(self)";
871 
872     const ImportMapEntry import_entry = {
873       GenPackageReference(field.value.type), TypeName(field)
874     };
875 
876     if (parser_.opts.python_typing) {
877       const std::string return_type = ReturnType(struct_def, field);
878       code += " -> Optional[" + return_type + "]";
879       imports.insert(ImportMapEntry{ "typing", "Optional" });
880       imports.insert(import_entry);
881     }
882     code += ":";
883     code += OffsetPrefix(field);
884     if (field.value.type.struct_def->fixed) {
885       code += Indent + Indent + Indent + "x = o + self._tab.Pos\n";
886     } else {
887       code += Indent + Indent + Indent;
888       code += "x = self._tab.Indirect(o + self._tab.Pos)\n";
889     }
890 
891     if (parser_.opts.include_dependence_headers &&
892         !parser_.opts.python_typing) {
893       code += Indent + Indent + Indent;
894       code += "from " + import_entry.first + " import " + import_entry.second +
895               "\n";
896     }
897     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
898     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
899     code += Indent + Indent + Indent + "return obj\n";
900     code += Indent + Indent + "return None\n\n";
901   }
902 
903   // Get the value of a string.
GetStringField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const904   void GetStringField(const StructDef &struct_def, const FieldDef &field,
905                       std::string *code_ptr, ImportMap &imports) const {
906     auto &code = *code_ptr;
907     GenReceiver(struct_def, code_ptr);
908     code += namer_.Method(field);
909 
910     if (parser_.opts.python_typing) {
911       code += "(self) -> Optional[str]:";
912       imports.insert(ImportMapEntry{ "typing", "Optional" });
913     } else {
914       code += "(self):";
915     }
916 
917     code += OffsetPrefix(field);
918     code += Indent + Indent + Indent + "return " + GenGetter(field.value.type);
919     code += "o + self._tab.Pos)\n";
920     code += Indent + Indent + "return None\n\n";
921   }
922 
923   // Get the value of a union from an object.
GetUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const924   void GetUnionField(const StructDef &struct_def, const FieldDef &field,
925                      std::string *code_ptr, ImportMap &imports) const {
926     auto &code = *code_ptr;
927     GenReceiver(struct_def, code_ptr);
928     std::string return_ty = "flatbuffers.table.Table";
929 
930     bool is_native_table = TypeName(field) == "*flatbuffers.Table";
931     ImportMapEntry import_entry;
932     if (is_native_table) {
933       import_entry = ImportMapEntry{ "flatbuffers.table", "Table" };
934     } else {
935       return_ty = TypeName(field);
936       import_entry = ImportMapEntry{ GenPackageReference(field.value.type),
937                                      TypeName(field) };
938     }
939 
940     code += namer_.Method(field) + "(self)";
941     if (parser_.opts.python_typing) {
942       code += " -> Optional[" + return_ty + "]";
943       imports.insert(ImportMapEntry{ "typing", "Optional" });
944       imports.insert(import_entry);
945     }
946     code += ":";
947     code += OffsetPrefix(field);
948 
949     if (!parser_.opts.python_typing) {
950       code += Indent + Indent + Indent;
951       code += "from " + import_entry.first + " import " + import_entry.second +
952               "\n";
953     }
954     code += Indent + Indent + Indent + "obj = Table(bytearray(), 0)\n";
955     code += Indent + Indent + Indent + GenGetter(field.value.type);
956     code += "obj, o)\n" + Indent + Indent + Indent + "return obj\n";
957     code += Indent + Indent + "return None\n\n";
958   }
959 
960   template <typename T>
ModuleFor(const T * def) const961   std::string ModuleFor(const T *def) const {
962     if (!parser_.opts.one_file) {
963       return namer_.NamespacedType(*def);
964     }
965 
966     std::string filename =
967         StripExtension(def->file) + parser_.opts.filename_suffix;
968     if (parser_.file_being_parsed_ == def->file) {
969       return "." + StripPath(filename);  // make it a "local" import
970     }
971 
972     std::string module = parser_.opts.include_prefix + filename;
973     std::replace(module.begin(), module.end(), '/', '.');
974     return module;
975   }
976 
977   // Generate the package reference when importing a struct or enum from its
978   // module.
GenPackageReference(const Type & type) const979   std::string GenPackageReference(const Type &type) const {
980     if (type.struct_def) return ModuleFor(type.struct_def);
981     if (type.enum_def) return ModuleFor(type.enum_def);
982     return "." + GenTypeGet(type);
983   }
984 
985   // Get the value of a vector's struct member.
GetMemberOfVectorOfStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const986   void GetMemberOfVectorOfStruct(const StructDef &struct_def,
987                                  const FieldDef &field, std::string *code_ptr,
988                                  ImportMap &imports) const {
989     auto &code = *code_ptr;
990     auto vectortype = field.value.type.VectorType();
991 
992     GenReceiver(struct_def, code_ptr);
993     code += namer_.Method(field);
994     const ImportMapEntry import_entry = {
995       GenPackageReference(field.value.type), TypeName(field)
996     };
997 
998     if (parser_.opts.python_typing) {
999       const std::string return_type = ReturnType(struct_def, field);
1000       code += "(self, j: int) -> Optional[" + return_type + "]";
1001       imports.insert(ImportMapEntry{ "typing", "Optional" });
1002       imports.insert(import_entry);
1003     } else {
1004       code += "(self, j)";
1005     }
1006     code += ":" + OffsetPrefix(field);
1007     code += Indent + Indent + Indent + "x = self._tab.Vector(o)\n";
1008     code += Indent + Indent + Indent;
1009     code += "x += flatbuffers.number_types.UOffsetTFlags.py_type(j) * ";
1010     code += NumToString(InlineSize(vectortype)) + "\n";
1011     if (!(vectortype.struct_def->fixed)) {
1012       code += Indent + Indent + Indent + "x = self._tab.Indirect(x)\n";
1013     }
1014     if (parser_.opts.include_dependence_headers &&
1015         !parser_.opts.python_typing) {
1016       code += Indent + Indent + Indent;
1017       code += "from " + import_entry.first + " import " + import_entry.second +
1018               "\n";
1019     }
1020     code += Indent + Indent + Indent + "obj = " + TypeName(field) + "()\n";
1021     code += Indent + Indent + Indent + "obj.Init(self._tab.Bytes, x)\n";
1022     code += Indent + Indent + Indent + "return obj\n";
1023     code += Indent + Indent + "return None\n\n";
1024   }
1025 
1026   // Get the value of a vector's non-struct member. Uses a named return
1027   // argument to conveniently set the zero value for the result.
GetMemberOfVectorOfNonStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1028   void GetMemberOfVectorOfNonStruct(const StructDef &struct_def,
1029                                     const FieldDef &field,
1030                                     std::string *code_ptr) const {
1031     auto &code = *code_ptr;
1032     auto vectortype = field.value.type.VectorType();
1033 
1034     GenReceiver(struct_def, code_ptr);
1035     code += namer_.Method(field);
1036     if (parser_.opts.python_typing) {
1037       code += "(self, j: int)";
1038     } else {
1039       code += "(self, j)";
1040     }
1041     code += ":";
1042     code += OffsetPrefix(field);
1043     code += Indent + Indent + Indent + "a = self._tab.Vector(o)\n";
1044     code += Indent + Indent + Indent;
1045     code += "return " + GenGetter(field.value.type);
1046     code += "a + flatbuffers.number_types.UOffsetTFlags.py_type(j * ";
1047     code += NumToString(InlineSize(vectortype)) + "))\n";
1048     if (IsString(vectortype)) {
1049       code += Indent + Indent + "return \"\"\n";
1050     } else {
1051       code += Indent + Indent + "return 0\n";
1052     }
1053     code += "\n";
1054   }
1055 
1056   // Returns a non-struct vector as a numpy array. Much faster
1057   // than iterating over the vector element by element.
GetVectorOfNonStructAsNumpy(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1058   void GetVectorOfNonStructAsNumpy(const StructDef &struct_def,
1059                                    const FieldDef &field,
1060                                    std::string *code_ptr) const {
1061     auto &code = *code_ptr;
1062     auto vectortype = field.value.type.VectorType();
1063 
1064     // Currently, we only support accessing as numpy array if
1065     // the vector type is a scalar.
1066     if (!(IsScalar(vectortype.base_type))) { return; }
1067 
1068     GenReceiver(struct_def, code_ptr);
1069     code += namer_.Method(field) + "AsNumpy(self):";
1070     if (!IsArray(field.value.type)) {
1071       code += OffsetPrefix(field, false);
1072 
1073       code += GenIndents(3);
1074       code += "return ";
1075       code += "self._tab.GetVectorAsNumpy(flatbuffers.number_types.";
1076       code += namer_.Method(GenTypeGet(field.value.type));
1077       code += "Flags, o)";
1078 
1079       if (IsString(vectortype)) {
1080         code += GenIndents(2) + "return \"\"\n";
1081       } else {
1082         code += GenIndents(2) + "return 0\n";
1083       }
1084     } else {
1085       code += GenIndents(2) + "return ";
1086       code += "self._tab.GetArrayAsNumpy(flatbuffers.number_types.";
1087       code += namer_.Method(GenTypeGet(field.value.type.VectorType()));
1088       code += "Flags, self._tab.Pos + " + NumToString(field.value.offset) +
1089               ", " + NumToString("self." + namer_.Method(field) + "Length()") +
1090               ")\n";
1091     }
1092     code += "\n";
1093   }
1094 
NestedFlatbufferType(std::string unqualified_name) const1095   std::string NestedFlatbufferType(std::string unqualified_name) const {
1096     StructDef *nested_root = parser_.LookupStruct(unqualified_name);
1097     std::string qualified_name;
1098     if (nested_root == nullptr) {
1099       qualified_name = namer_.NamespacedType(
1100           parser_.current_namespace_->components, unqualified_name);
1101       // Double check qualified name just to be sure it exists.
1102       nested_root = parser_.LookupStruct(qualified_name);
1103     }
1104     FLATBUFFERS_ASSERT(nested_root);  // Guaranteed to exist by parser.
1105     return qualified_name;
1106   }
1107 
1108   // Returns a nested flatbuffer as itself.
GetVectorAsNestedFlatbuffer(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const1109   void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
1110                                    const FieldDef &field, std::string *code_ptr,
1111                                    ImportMap &imports) const {
1112     auto nested = field.attributes.Lookup("nested_flatbuffer");
1113     if (!nested) { return; }  // There is no nested flatbuffer.
1114 
1115     const std::string unqualified_name = nested->constant;
1116     std::string qualified_name = NestedFlatbufferType(unqualified_name);
1117     if (qualified_name.empty()) { qualified_name = nested->constant; }
1118 
1119     const ImportMapEntry import_entry = { qualified_name,
1120                                           unqualified_name };
1121 
1122     auto &code = *code_ptr;
1123     GenReceiver(struct_def, code_ptr);
1124     code += namer_.Method(field) + "NestedRoot(self)";
1125     if (parser_.opts.python_typing) {
1126       code += " -> Union[" + unqualified_name + ", int]";
1127       imports.insert(ImportMapEntry{ "typing", "Union" });
1128       imports.insert(import_entry);
1129     }
1130     code += ":";
1131 
1132     code += OffsetPrefix(field);
1133 
1134     if (!parser_.opts.python_typing) {
1135       code += Indent + Indent + Indent;
1136       code += "from " + import_entry.first + " import " + import_entry.second +
1137               "\n";
1138     }
1139     code += Indent + Indent + Indent + "return " + unqualified_name;
1140     code += ".GetRootAs";
1141     code += "(self._tab.Bytes, self._tab.Vector(o))\n";
1142     code += Indent + Indent + "return 0\n";
1143     code += "\n";
1144   }
1145 
1146   // Begin the creator function signature.
BeginBuilderArgs(const StructDef & struct_def,std::string * code_ptr) const1147   void BeginBuilderArgs(const StructDef &struct_def,
1148                         std::string *code_ptr) const {
1149     auto &code = *code_ptr;
1150 
1151     code += "\n";
1152     code += "def Create" + namer_.Type(struct_def);
1153     code += "(builder";
1154   }
1155 
1156   // Recursively generate arguments for a constructor, to deal with nested
1157   // 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) const1158   void StructBuilderArgs(const StructDef &struct_def,
1159                          const std::string nameprefix,
1160                          const std::string namesuffix, bool has_field_name,
1161                          const std::string fieldname_suffix,
1162                          std::string *code_ptr) const {
1163     for (auto it = struct_def.fields.vec.begin();
1164          it != struct_def.fields.vec.end(); ++it) {
1165       auto &field = **it;
1166       const auto &field_type = field.value.type;
1167       const auto &type =
1168           IsArray(field_type) ? field_type.VectorType() : field_type;
1169       if (IsStruct(type)) {
1170         // Generate arguments for a struct inside a struct. To ensure names
1171         // don't clash, and to make it obvious these arguments are constructing
1172         // a nested struct, prefix the name with the field name.
1173         auto subprefix = nameprefix;
1174         if (has_field_name) {
1175           subprefix += namer_.Field(field) + fieldname_suffix;
1176         }
1177         StructBuilderArgs(*field.value.type.struct_def, subprefix, namesuffix,
1178                           has_field_name, fieldname_suffix, code_ptr);
1179       } else {
1180         auto &code = *code_ptr;
1181         code += std::string(", ") + nameprefix;
1182         if (has_field_name) { code += namer_.Field(field); }
1183         code += namesuffix;
1184       }
1185     }
1186   }
1187 
1188   // End the creator function signature.
EndBuilderArgs(std::string * code_ptr) const1189   void EndBuilderArgs(std::string *code_ptr) const {
1190     auto &code = *code_ptr;
1191     code += "):\n";
1192   }
1193 
1194   // Recursively generate struct construction statements and instert manual
1195   // padding.
StructBuilderBody(const StructDef & struct_def,const char * nameprefix,std::string * code_ptr,size_t index=0,bool in_array=false) const1196   void StructBuilderBody(const StructDef &struct_def, const char *nameprefix,
1197                          std::string *code_ptr, size_t index = 0,
1198                          bool in_array = false) const {
1199     auto &code = *code_ptr;
1200     std::string indent(index * 4, ' ');
1201     code +=
1202         indent + "    builder.Prep(" + NumToString(struct_def.minalign) + ", ";
1203     code += NumToString(struct_def.bytesize) + ")\n";
1204     for (auto it = struct_def.fields.vec.rbegin();
1205          it != struct_def.fields.vec.rend(); ++it) {
1206       auto &field = **it;
1207       const auto &field_type = field.value.type;
1208       const auto &type =
1209           IsArray(field_type) ? field_type.VectorType() : field_type;
1210       if (field.padding)
1211         code +=
1212             indent + "    builder.Pad(" + NumToString(field.padding) + ")\n";
1213       if (IsStruct(field_type)) {
1214         StructBuilderBody(*field_type.struct_def,
1215                           (nameprefix + (namer_.Field(field) + "_")).c_str(),
1216                           code_ptr, index, in_array);
1217       } else {
1218         const auto index_var = "_idx" + NumToString(index);
1219         if (IsArray(field_type)) {
1220           code += indent + "    for " + index_var + " in range(";
1221           code += NumToString(field_type.fixed_length);
1222           code += " , 0, -1):\n";
1223           in_array = true;
1224         }
1225         if (IsStruct(type)) {
1226           StructBuilderBody(*field_type.struct_def,
1227                             (nameprefix + (namer_.Field(field) + "_")).c_str(),
1228                             code_ptr, index + 1, in_array);
1229         } else {
1230           code += IsArray(field_type) ? "    " : "";
1231           code += indent + "    builder.Prepend" + GenMethod(field) + "(";
1232           code += nameprefix + namer_.Variable(field);
1233           size_t array_cnt = index + (IsArray(field_type) ? 1 : 0);
1234           for (size_t i = 0; in_array && i < array_cnt; i++) {
1235             code += "[_idx" + NumToString(i) + "-1]";
1236           }
1237           code += ")\n";
1238         }
1239       }
1240     }
1241   }
1242 
EndBuilderBody(std::string * code_ptr) const1243   void EndBuilderBody(std::string *code_ptr) const {
1244     auto &code = *code_ptr;
1245     code += "    return builder.Offset()\n";
1246   }
1247 
1248   // Get the value of a table's starting offset.
GetStartOfTable(const StructDef & struct_def,std::string * code_ptr) const1249   void GetStartOfTable(const StructDef &struct_def,
1250                        std::string *code_ptr) const {
1251     auto &code = *code_ptr;
1252     const auto struct_type = namer_.Type(struct_def);
1253     // Generate method with struct name.
1254 
1255     const auto name = parser_.opts.python_no_type_prefix_suffix
1256                           ? "Start"
1257                           : struct_type + "Start";
1258 
1259     code += "def " + name;
1260     if (parser_.opts.python_typing) {
1261       code += "(builder: flatbuffers.Builder):\n";
1262     } else {
1263       code += "(builder):\n";
1264     }
1265 
1266     code += Indent + "builder.StartObject(";
1267     code += NumToString(struct_def.fields.vec.size());
1268     code += ")\n\n";
1269 
1270     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
1271       // Generate method without struct name.
1272       if (parser_.opts.python_typing) {
1273         code += "def Start(builder: flatbuffers.Builder):\n";
1274       } else {
1275         code += "def Start(builder):\n";
1276       }
1277       code += Indent + struct_type + "Start(builder)\n\n";
1278     }
1279   }
1280 
1281   // Set the value of a table's field.
BuildFieldOfTable(const StructDef & struct_def,const FieldDef & field,const size_t offset,std::string * code_ptr) const1282   void BuildFieldOfTable(const StructDef &struct_def, const FieldDef &field,
1283                          const size_t offset, std::string *code_ptr) const {
1284     auto &code = *code_ptr;
1285     const std::string field_var = namer_.Variable(field);
1286     const std::string field_method = namer_.Method(field);
1287     const std::string field_ty = GenFieldTy(field);
1288 
1289     const auto name = parser_.opts.python_no_type_prefix_suffix
1290                           ? "Add" + field_method
1291                           : namer_.Type(struct_def) + "Add" + field_method;
1292 
1293     // Generate method with struct name.
1294     code += "def " + name;
1295     if (parser_.opts.python_typing) {
1296       code += "(builder: flatbuffers.Builder, " + field_var + ": " + field_ty;
1297     } else {
1298       code += "(builder, " + field_var;
1299     }
1300     code += "):\n";
1301     code += Indent + "builder.Prepend";
1302     code += GenMethod(field) + "Slot(";
1303     code += NumToString(offset) + ", ";
1304     if (!IsScalar(field.value.type.base_type) && (!struct_def.fixed)) {
1305       code += "flatbuffers.number_types.UOffsetTFlags.py_type";
1306       code += "(" + field_var + ")";
1307     } else {
1308       code += field_var;
1309     }
1310     code += ", ";
1311     if (field.IsScalarOptional()) {
1312       code += "None";
1313     } else if (IsFloat(field.value.type.base_type)) {
1314       code += float_const_gen_.GenFloatConstant(field);
1315     } else {
1316       code += field.value.constant;
1317     }
1318     code += ")\n\n";
1319 
1320     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
1321       // Generate method without struct name.
1322       code += "def Add" + field_method;
1323       if (parser_.opts.python_typing) {
1324         code += "(builder: flatbuffers.Builder, " + field_var + ": " + field_ty;
1325       } else {
1326         code += "(builder, " + field_var;
1327       }
1328       code += "):\n";
1329       code += Indent + namer_.Type(struct_def) + "Add" + field_method;
1330       code += "(builder, ";
1331       code += field_var;
1332       code += ")\n\n";
1333     }
1334   }
1335 
1336   // 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) const1337   void BuildVectorOfTable(const StructDef &struct_def, const FieldDef &field,
1338                           std::string *code_ptr) const {
1339     auto &code = *code_ptr;
1340     const std::string struct_type = namer_.Type(struct_def);
1341     const std::string field_method = namer_.Method(field);
1342 
1343     // Generate method with struct name.
1344     const auto name = parser_.opts.python_no_type_prefix_suffix
1345                           ? "Start" + field_method
1346                           : struct_type + "Start" + field_method;
1347     code += "def " + name;
1348     if (parser_.opts.python_typing) {
1349       code += "Vector(builder, numElems: int) -> int:\n";
1350     } else {
1351       code += "Vector(builder, numElems):\n";
1352     }
1353 
1354     code += Indent + "return builder.StartVector(";
1355     auto vector_type = field.value.type.VectorType();
1356     auto alignment = InlineAlignment(vector_type);
1357     auto elem_size = InlineSize(vector_type);
1358     code += NumToString(elem_size);
1359     code += ", numElems, " + NumToString(alignment);
1360     code += ")\n\n";
1361 
1362     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
1363       // Generate method without struct name.
1364       if (parser_.opts.python_typing) {
1365         code += "def Start" + field_method +
1366                 "Vector(builder, numElems: int) -> int:\n";
1367       } else {
1368         code += "def Start" + field_method + "Vector(builder, numElems):\n";
1369       }
1370       code += Indent + "return " + struct_type + "Start";
1371       code += field_method + "Vector(builder, numElems)\n\n";
1372     }
1373   }
1374 
1375   // Set the value of one of the members of a table's vector and fills in the
1376   // elements from a bytearray. This is for simplifying the use of nested
1377   // flatbuffers.
BuildVectorOfTableFromBytes(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1378   void BuildVectorOfTableFromBytes(const StructDef &struct_def,
1379                                    const FieldDef &field,
1380                                    std::string *code_ptr) const {
1381     auto nested = field.attributes.Lookup("nested_flatbuffer");
1382     if (!nested) { return; }  // There is no nested flatbuffer.
1383 
1384     auto &code = *code_ptr;
1385     const std::string field_method = namer_.Method(field);
1386     const std::string struct_type = namer_.Type(struct_def);
1387 
1388     // Generate method with struct and field name.
1389     code += "def " + struct_type + "Make" + field_method;
1390     code += "VectorFromBytes(builder, bytes):\n";
1391     code += Indent + "builder.StartVector(";
1392     auto vector_type = field.value.type.VectorType();
1393     auto alignment = InlineAlignment(vector_type);
1394     auto elem_size = InlineSize(vector_type);
1395     code += NumToString(elem_size);
1396     code += ", len(bytes), " + NumToString(alignment);
1397     code += ")\n";
1398     code += Indent + "builder.head = builder.head - len(bytes)\n";
1399     code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
1400     code += " = bytes\n";
1401     code += Indent + "return builder.EndVector()\n";
1402 
1403     if (!parser_.opts.one_file) {
1404       // Generate method without struct and field name.
1405       code += "def Make" + field_method + "VectorFromBytes(builder, bytes):\n";
1406       code += Indent + "return " + struct_type + "Make" + field_method +
1407               "VectorFromBytes(builder, bytes)\n";
1408     }
1409   }
1410 
1411   // Get the offset of the end of a table.
GetEndOffsetOnTable(const StructDef & struct_def,std::string * code_ptr) const1412   void GetEndOffsetOnTable(const StructDef &struct_def,
1413                            std::string *code_ptr) const {
1414     auto &code = *code_ptr;
1415 
1416     const auto name = parser_.opts.python_no_type_prefix_suffix
1417                           ? "End"
1418                           : namer_.Type(struct_def) + "End";
1419     // Generate method with struct name.
1420     if (parser_.opts.python_typing) {
1421       code += "def " + name + "(builder: flatbuffers.Builder) -> int:\n";
1422     } else {
1423       code += "def " + name + "(builder):\n";
1424     }
1425     code += Indent + "return builder.EndObject()\n\n";
1426 
1427     if (!parser_.opts.one_file && !parser_.opts.python_no_type_prefix_suffix) {
1428       // Generate method without struct name.
1429       if (parser_.opts.python_typing) {
1430         code += "def End(builder: flatbuffers.Builder) -> int:\n";
1431       } else {
1432         code += "def End(builder):\n";
1433       }
1434       code += Indent + "return " + namer_.Type(struct_def) + "End(builder)";
1435       code += "\n";
1436     }
1437   }
1438 
1439   // Generate the receiver for function signatures.
GenReceiver(const StructDef & struct_def,std::string * code_ptr) const1440   void GenReceiver(const StructDef &struct_def, std::string *code_ptr) const {
1441     auto &code = *code_ptr;
1442     code += Indent + "# " + namer_.Type(struct_def) + "\n";
1443     code += Indent + "def ";
1444   }
1445 
1446   // Generate a struct field, conditioned on its child type(s).
GenStructAccessor(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,ImportMap & imports) const1447   void GenStructAccessor(const StructDef &struct_def, const FieldDef &field,
1448                          std::string *code_ptr, ImportMap &imports) const {
1449     GenComment(field.doc_comment, code_ptr, &def_comment, Indent.c_str());
1450     if (IsScalar(field.value.type.base_type)) {
1451       if (struct_def.fixed) {
1452         GetScalarFieldOfStruct(struct_def, field, code_ptr);
1453       } else {
1454         GetScalarFieldOfTable(struct_def, field, code_ptr);
1455       }
1456     } else {
1457       switch (field.value.type.base_type) {
1458         case BASE_TYPE_STRUCT:
1459           if (struct_def.fixed) {
1460             GetStructFieldOfStruct(struct_def, field, code_ptr);
1461           } else {
1462             GetStructFieldOfTable(struct_def, field, code_ptr, imports);
1463           }
1464           break;
1465         case BASE_TYPE_STRING:
1466           GetStringField(struct_def, field, code_ptr, imports);
1467           break;
1468         case BASE_TYPE_VECTOR: {
1469           auto vectortype = field.value.type.VectorType();
1470           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1471             GetMemberOfVectorOfStruct(struct_def, field, code_ptr, imports);
1472           } else {
1473             GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
1474             if (parser_.opts.python_gen_numpy) {
1475               GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
1476             }
1477             GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr, imports);
1478           }
1479           break;
1480         }
1481         case BASE_TYPE_ARRAY: {
1482           auto vectortype = field.value.type.VectorType();
1483           if (vectortype.base_type == BASE_TYPE_STRUCT) {
1484             GetArrayOfStruct(struct_def, field, code_ptr, imports);
1485           } else {
1486             GetArrayOfNonStruct(struct_def, field, code_ptr);
1487             if (parser_.opts.python_gen_numpy) {
1488               GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
1489             }
1490             GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr, imports);
1491           }
1492           break;
1493         }
1494         case BASE_TYPE_UNION:
1495           GetUnionField(struct_def, field, code_ptr, imports);
1496           break;
1497         default: FLATBUFFERS_ASSERT(0);
1498       }
1499     }
1500     if (IsVector(field.value.type) || IsArray(field.value.type)) {
1501       GetVectorLen(struct_def, field, code_ptr);
1502       GetVectorIsNone(struct_def, field, code_ptr);
1503     }
1504   }
1505 
1506   // Generate struct sizeof.
GenStructSizeOf(const StructDef & struct_def,std::string * code_ptr) const1507   void GenStructSizeOf(const StructDef &struct_def,
1508                        std::string *code_ptr) const {
1509     auto &code = *code_ptr;
1510     code += Indent + "@classmethod\n";
1511     if (parser_.opts.python_typing) {
1512       code += Indent + "def SizeOf(cls) -> int:\n";
1513     } else {
1514       code += Indent + "def SizeOf(cls):\n";
1515     }
1516     code +=
1517         Indent + Indent + "return " + NumToString(struct_def.bytesize) + "\n";
1518     code += "\n";
1519   }
1520 
1521   // Generate table constructors, conditioned on its members' types.
GenTableBuilders(const StructDef & struct_def,std::string * code_ptr) const1522   void GenTableBuilders(const StructDef &struct_def,
1523                         std::string *code_ptr) const {
1524     GetStartOfTable(struct_def, code_ptr);
1525 
1526     for (auto it = struct_def.fields.vec.begin();
1527          it != struct_def.fields.vec.end(); ++it) {
1528       auto &field = **it;
1529       if (field.deprecated) continue;
1530 
1531       auto offset = it - struct_def.fields.vec.begin();
1532       BuildFieldOfTable(struct_def, field, offset, code_ptr);
1533       if (IsVector(field.value.type)) {
1534         BuildVectorOfTable(struct_def, field, code_ptr);
1535         BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
1536       }
1537     }
1538 
1539     GetEndOffsetOnTable(struct_def, code_ptr);
1540   }
1541 
1542   // Generate function to check for proper file identifier
GenHasFileIdentifier(const StructDef & struct_def,std::string * code_ptr) const1543   void GenHasFileIdentifier(const StructDef &struct_def,
1544                             std::string *code_ptr) const {
1545     auto &code = *code_ptr;
1546     std::string escapedID;
1547     // In the event any of file_identifier characters are special(NULL, \, etc),
1548     // problems occur. To prevent this, convert all chars to their hex-escaped
1549     // equivalent.
1550     for (auto it = parser_.file_identifier_.begin();
1551          it != parser_.file_identifier_.end(); ++it) {
1552       escapedID += "\\x" + IntToStringHex(*it, 2);
1553     }
1554 
1555     code += Indent + "@classmethod\n";
1556     code += Indent + "def " + namer_.Type(struct_def);
1557     code += "BufferHasIdentifier(cls, buf, offset, size_prefixed=False):";
1558     code += "\n";
1559     code += Indent + Indent;
1560     code += "return flatbuffers.util.BufferHasIdentifier(buf, offset, b\"";
1561     code += escapedID;
1562     code += "\", size_prefixed=size_prefixed)\n";
1563     code += "\n";
1564   }
1565 
1566   // Generates struct or table methods.
GenStruct(const StructDef & struct_def,std::string * code_ptr,ImportMap & imports) const1567   void GenStruct(const StructDef &struct_def, std::string *code_ptr,
1568                  ImportMap &imports) const {
1569     if (struct_def.generated) return;
1570 
1571     GenComment(struct_def.doc_comment, code_ptr, &def_comment);
1572     BeginClass(struct_def, code_ptr);
1573     if (!struct_def.fixed) {
1574       // Generate a special accessor for the table that has been declared as
1575       // the root type.
1576       NewRootTypeFromBuffer(struct_def, code_ptr);
1577       if (parser_.file_identifier_.length()) {
1578         // Generate a special function to test file_identifier
1579         GenHasFileIdentifier(struct_def, code_ptr);
1580       }
1581     } else {
1582       // Generates the SizeOf method for all structs.
1583       GenStructSizeOf(struct_def, code_ptr);
1584     }
1585     // Generates the Init method that sets the field in a pre-existing
1586     // accessor object. This is to allow object reuse.
1587     InitializeExisting(struct_def, code_ptr);
1588     for (auto it = struct_def.fields.vec.begin();
1589          it != struct_def.fields.vec.end(); ++it) {
1590       auto &field = **it;
1591       if (field.deprecated) continue;
1592 
1593       GenStructAccessor(struct_def, field, code_ptr, imports);
1594     }
1595 
1596     if (struct_def.fixed) {
1597       // creates a struct constructor function
1598       GenStructBuilder(struct_def, code_ptr);
1599     } else {
1600       // Creates a set of functions that allow table construction.
1601       GenTableBuilders(struct_def, code_ptr);
1602     }
1603   }
1604 
GenReceiverForObjectAPI(const StructDef & struct_def,std::string * code_ptr) const1605   void GenReceiverForObjectAPI(const StructDef &struct_def,
1606                                std::string *code_ptr) const {
1607     auto &code = *code_ptr;
1608     code += GenIndents(1) + "# " + namer_.ObjectType(struct_def);
1609     code += GenIndents(1) + "def ";
1610   }
1611 
BeginClassForObjectAPI(const StructDef & struct_def,std::string * code_ptr) const1612   void BeginClassForObjectAPI(const StructDef &struct_def,
1613                               std::string *code_ptr) const {
1614     auto &code = *code_ptr;
1615     code += "\n";
1616     code += "class " + namer_.ObjectType(struct_def) + "(object):";
1617     code += "\n";
1618   }
1619 
1620   // Gets the accoresponding python builtin type of a BaseType for scalars and
1621   // string.
GetBasePythonTypeForScalarAndString(const BaseType & base_type) const1622   std::string GetBasePythonTypeForScalarAndString(
1623       const BaseType &base_type) const {
1624     if (IsBool(base_type)) {
1625       return "bool";
1626     } else if (IsFloat(base_type)) {
1627       return "float";
1628     } else if (IsInteger(base_type)) {
1629       return "int";
1630     } else if (base_type == BASE_TYPE_STRING) {
1631       return "str";
1632     } else {
1633       FLATBUFFERS_ASSERT(false && "base_type is not a scalar or string type.");
1634       return "";
1635     }
1636   }
1637 
GetDefaultValue(const FieldDef & field) const1638   std::string GetDefaultValue(const FieldDef &field) const {
1639     BaseType base_type = field.value.type.base_type;
1640     if (field.IsScalarOptional()) {
1641       return "None";
1642     } else if (IsBool(base_type)) {
1643       return field.value.constant == "0" ? "False" : "True";
1644     } else if (IsFloat(base_type)) {
1645       return float_const_gen_.GenFloatConstant(field);
1646     } else if (IsInteger(base_type)) {
1647       return field.value.constant;
1648     } else {
1649       // For string, struct, and table.
1650       return "None";
1651     }
1652   }
1653 
GenUnionInit(const FieldDef & field,std::string * field_types_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list) const1654   void GenUnionInit(const FieldDef &field, std::string *field_types_ptr,
1655                     std::set<std::string> *import_list,
1656                     std::set<std::string> *import_typing_list) const {
1657     // Gets all possible types in the union.
1658     import_typing_list->insert("Union");
1659     auto &field_types = *field_types_ptr;
1660     field_types = "Union[";
1661 
1662     std::string separator_string = ", ";
1663     auto enum_def = field.value.type.enum_def;
1664     for (auto it = enum_def->Vals().begin(); it != enum_def->Vals().end();
1665          ++it) {
1666       auto &ev = **it;
1667       // Union only supports string and table.
1668       std::string field_type;
1669       switch (ev.union_type.base_type) {
1670         case BASE_TYPE_STRUCT:
1671           field_type = namer_.ObjectType(*ev.union_type.struct_def);
1672           if (parser_.opts.include_dependence_headers) {
1673             auto package_reference = GenPackageReference(ev.union_type);
1674             field_type = package_reference + "." + field_type;
1675             import_list->insert("import " + package_reference);
1676           }
1677           break;
1678         case BASE_TYPE_STRING: field_type += "str"; break;
1679         case BASE_TYPE_NONE: field_type += "None"; break;
1680         default: break;
1681       }
1682       field_types += field_type + separator_string;
1683     }
1684 
1685     // Removes the last separator_string.
1686     field_types.erase(field_types.length() - separator_string.size());
1687     field_types += "]";
1688 
1689     // Gets the import lists for the union.
1690     if (parser_.opts.include_dependence_headers) {
1691       const auto package_reference = GenPackageReference(field.value.type);
1692       import_list->insert("import " + package_reference);
1693     }
1694   }
1695 
GenStructInit(const FieldDef & field,std::string * out_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list) const1696   void GenStructInit(const FieldDef &field, std::string *out_ptr,
1697                      std::set<std::string> *import_list,
1698                      std::set<std::string> *import_typing_list) const {
1699     import_typing_list->insert("Optional");
1700     auto &output = *out_ptr;
1701     const Type &type = field.value.type;
1702     const std::string object_type = namer_.ObjectType(*type.struct_def);
1703     if (parser_.opts.include_dependence_headers) {
1704       auto package_reference = GenPackageReference(type);
1705       output = package_reference + "." + object_type + "]";
1706       import_list->insert("import " + package_reference);
1707     } else {
1708       output = object_type + "]";
1709     }
1710     output = "Optional[" + output;
1711   }
1712 
GenVectorInit(const FieldDef & field,std::string * field_type_ptr,std::set<std::string> * import_list,std::set<std::string> * import_typing_list) const1713   void GenVectorInit(const FieldDef &field, std::string *field_type_ptr,
1714                      std::set<std::string> *import_list,
1715                      std::set<std::string> *import_typing_list) const {
1716     import_typing_list->insert("List");
1717     auto &field_type = *field_type_ptr;
1718     const Type &vector_type = field.value.type.VectorType();
1719     const BaseType base_type = vector_type.base_type;
1720     if (base_type == BASE_TYPE_STRUCT) {
1721       const std::string object_type =
1722           namer_.ObjectType(*vector_type.struct_def);
1723       field_type = object_type + "]";
1724       if (parser_.opts.include_dependence_headers) {
1725         auto package_reference = GenPackageReference(vector_type);
1726         field_type = package_reference + "." + object_type + "]";
1727         import_list->insert("import " + package_reference);
1728       }
1729       field_type = "List[" + field_type;
1730     } else {
1731       field_type =
1732           "List[" + GetBasePythonTypeForScalarAndString(base_type) + "]";
1733     }
1734   }
1735 
GenInitialize(const StructDef & struct_def,std::string * code_ptr,std::set<std::string> * import_list) const1736   void GenInitialize(const StructDef &struct_def, std::string *code_ptr,
1737                      std::set<std::string> *import_list) const {
1738     std::string code;
1739     std::set<std::string> import_typing_list;
1740     for (auto it = struct_def.fields.vec.begin();
1741          it != struct_def.fields.vec.end(); ++it) {
1742       auto &field = **it;
1743       if (field.deprecated) continue;
1744 
1745       // Determines field type, default value, and typing imports.
1746       auto base_type = field.value.type.base_type;
1747       std::string field_type;
1748       switch (base_type) {
1749         case BASE_TYPE_UNION: {
1750           GenUnionInit(field, &field_type, import_list, &import_typing_list);
1751           break;
1752         }
1753         case BASE_TYPE_STRUCT: {
1754           GenStructInit(field, &field_type, import_list, &import_typing_list);
1755           break;
1756         }
1757         case BASE_TYPE_VECTOR:
1758         case BASE_TYPE_ARRAY: {
1759           GenVectorInit(field, &field_type, import_list, &import_typing_list);
1760           break;
1761         }
1762         default:
1763           // Scalar or sting fields.
1764           field_type = GetBasePythonTypeForScalarAndString(base_type);
1765           if (field.IsScalarOptional()) {
1766             field_type = "Optional[" + field_type + "]";
1767           }
1768           break;
1769       }
1770 
1771       const auto default_value = GetDefaultValue(field);
1772       // Wrties the init statement.
1773       const auto field_field = namer_.Field(field);
1774       code += GenIndents(2) + "self." + field_field + " = " + default_value +
1775               "  # type: " + field_type;
1776     }
1777 
1778     // Writes __init__ method.
1779     auto &code_base = *code_ptr;
1780     GenReceiverForObjectAPI(struct_def, code_ptr);
1781     code_base += "__init__(self):";
1782     if (code.empty()) {
1783       code_base += GenIndents(2) + "pass";
1784     } else {
1785       code_base += code;
1786     }
1787     code_base += "\n";
1788 
1789     // Merges the typing imports into import_list.
1790     if (!import_typing_list.empty()) {
1791       // Adds the try statement.
1792       std::string typing_imports = "try:";
1793       typing_imports += GenIndents(1) + "from typing import ";
1794       std::string separator_string = ", ";
1795       for (auto it = import_typing_list.begin(); it != import_typing_list.end();
1796            ++it) {
1797         const std::string &im = *it;
1798         typing_imports += im + separator_string;
1799       }
1800       // Removes the last separator_string.
1801       typing_imports.erase(typing_imports.length() - separator_string.size());
1802 
1803       // Adds the except statement.
1804       typing_imports += "\n";
1805       typing_imports += "except:";
1806       typing_imports += GenIndents(1) + "pass";
1807       import_list->insert(typing_imports);
1808     }
1809 
1810     // Removes the import of the struct itself, if applied.
1811     auto struct_import = "import " + namer_.NamespacedType(struct_def);
1812     import_list->erase(struct_import);
1813   }
1814 
InitializeFromBuf(const StructDef & struct_def,std::string * code_ptr) const1815   void InitializeFromBuf(const StructDef &struct_def,
1816                          std::string *code_ptr) const {
1817     auto &code = *code_ptr;
1818     const auto struct_var = namer_.Variable(struct_def);
1819     const auto struct_type = namer_.Type(struct_def);
1820 
1821     code += GenIndents(1) + "@classmethod";
1822     code += GenIndents(1) + "def InitFromBuf(cls, buf, pos):";
1823     code += GenIndents(2) + struct_var + " = " + struct_type + "()";
1824     code += GenIndents(2) + struct_var + ".Init(buf, pos)";
1825     code += GenIndents(2) + "return cls.InitFromObj(" + struct_var + ")";
1826     code += "\n";
1827   }
1828 
InitializeFromPackedBuf(const StructDef & struct_def,std::string * code_ptr) const1829   void InitializeFromPackedBuf(const StructDef &struct_def,
1830                                std::string *code_ptr) const {
1831     auto &code = *code_ptr;
1832     const auto struct_var = namer_.Variable(struct_def);
1833     const auto struct_type = namer_.Type(struct_def);
1834 
1835     code += GenIndents(1) + "@classmethod";
1836     code += GenIndents(1) + "def InitFromPackedBuf(cls, buf, pos=0):";
1837     code += GenIndents(2) +
1838             "n = flatbuffers.encode.Get(flatbuffers.packer.uoffset, buf, pos)";
1839     code += GenIndents(2) + "return cls.InitFromBuf(buf, pos+n)";
1840     code += "\n";
1841   }
1842 
InitializeFromObjForObject(const StructDef & struct_def,std::string * code_ptr) const1843   void InitializeFromObjForObject(const StructDef &struct_def,
1844                                   std::string *code_ptr) const {
1845     auto &code = *code_ptr;
1846     const auto struct_var = namer_.Variable(struct_def);
1847     const auto struct_object = namer_.ObjectType(struct_def);
1848 
1849     code += GenIndents(1) + "@classmethod";
1850     code += GenIndents(1) + "def InitFromObj(cls, " + struct_var + "):";
1851     code += GenIndents(2) + "x = " + struct_object + "()";
1852     code += GenIndents(2) + "x._UnPack(" + struct_var + ")";
1853     code += GenIndents(2) + "return x";
1854     code += "\n";
1855   }
1856 
GenCompareOperator(const StructDef & struct_def,std::string * code_ptr) const1857   void GenCompareOperator(const StructDef &struct_def,
1858                           std::string *code_ptr) const {
1859     auto &code = *code_ptr;
1860     code += GenIndents(1) + "def __eq__(self, other):";
1861     code += GenIndents(2) + "return type(self) == type(other)";
1862     for (auto it = struct_def.fields.vec.begin();
1863          it != struct_def.fields.vec.end(); ++it) {
1864       auto &field = **it;
1865       if (field.deprecated) continue;
1866 
1867       // Wrties the comparison statement for this field.
1868       const auto field_field = namer_.Field(field);
1869       code += " and \\" + GenIndents(3) + "self." + field_field +
1870               " == " + "other." + field_field;
1871     }
1872     code += "\n";
1873   }
1874 
GenUnPackForStruct(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1875   void GenUnPackForStruct(const StructDef &struct_def, const FieldDef &field,
1876                           std::string *code_ptr) const {
1877     auto &code = *code_ptr;
1878     const auto struct_var = namer_.Variable(struct_def);
1879     const auto field_field = namer_.Field(field);
1880     const auto field_method = namer_.Method(field);
1881     auto field_type = TypeName(field);
1882 
1883     if (parser_.opts.include_dependence_headers) {
1884       auto package_reference = GenPackageReference(field.value.type);
1885       field_type = package_reference + "." + TypeName(field);
1886     }
1887 
1888     code += GenIndents(2) + "if " + struct_var + "." + field_method + "(";
1889     // if field is a struct, we need to create an instance for it first.
1890     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1891       code += field_type + "()";
1892     }
1893     code += ") is not None:";
1894     code += GenIndents(3) + "self." + field_field + " = " +
1895             namer_.ObjectType(field_type) + +".InitFromObj(" + struct_var +
1896             "." + field_method + "(";
1897     // A struct's accessor requires a struct buf instance.
1898     if (struct_def.fixed && field.value.type.base_type == BASE_TYPE_STRUCT) {
1899       code += field_type + "()";
1900     }
1901     code += "))";
1902   }
1903 
GenUnPackForUnion(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1904   void GenUnPackForUnion(const StructDef &struct_def, const FieldDef &field,
1905                          std::string *code_ptr) const {
1906     auto &code = *code_ptr;
1907     const auto field_field = namer_.Field(field);
1908     const auto field_method = namer_.Method(field);
1909     const auto struct_var = namer_.Variable(struct_def);
1910     const EnumDef &enum_def = *field.value.type.enum_def;
1911     auto union_type = namer_.Type(enum_def);
1912 
1913     if (parser_.opts.include_dependence_headers) {
1914       union_type = namer_.NamespacedType(enum_def) + "." + union_type;
1915     }
1916     code += GenIndents(2) + "self." + field_field + " = " + union_type +
1917             "Creator(" + "self." + field_field + "Type, " + struct_var + "." +
1918             field_method + "())";
1919   }
1920 
GenUnPackForStructVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1921   void GenUnPackForStructVector(const StructDef &struct_def,
1922                                 const FieldDef &field,
1923                                 std::string *code_ptr) const {
1924     auto &code = *code_ptr;
1925     const auto field_field = namer_.Field(field);
1926     const auto field_method = namer_.Method(field);
1927     const auto struct_var = namer_.Variable(struct_def);
1928 
1929     code += GenIndents(2) + "if not " + struct_var + "." + field_method +
1930             "IsNone():";
1931     code += GenIndents(3) + "self." + field_field + " = []";
1932     code += GenIndents(3) + "for i in range(" + struct_var + "." +
1933             field_method + "Length()):";
1934 
1935     auto field_type = TypeName(field);
1936     auto one_instance = field_type + "_";
1937     one_instance[0] = CharToLower(one_instance[0]);
1938     if (parser_.opts.include_dependence_headers) {
1939       auto package_reference = GenPackageReference(field.value.type);
1940       field_type = package_reference + "." + TypeName(field);
1941     }
1942     code += GenIndents(4) + "if " + struct_var + "." + field_method +
1943             "(i) is None:";
1944     code += GenIndents(5) + "self." + field_field + ".append(None)";
1945     code += GenIndents(4) + "else:";
1946     code += GenIndents(5) + one_instance + " = " +
1947             namer_.ObjectType(field_type) + ".InitFromObj(" + struct_var + "." +
1948             field_method + "(i))";
1949     code +=
1950         GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
1951   }
1952 
GenUnpackForTableVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const1953   void GenUnpackForTableVector(const StructDef &struct_def,
1954                                const FieldDef &field,
1955                                std::string *code_ptr) const {
1956     auto &code = *code_ptr;
1957     const auto field_field = namer_.Field(field);
1958     const auto field_method = namer_.Method(field);
1959     const auto struct_var = namer_.Variable(struct_def);
1960 
1961     code += GenIndents(2) + "if not " + struct_var + "." + field_method +
1962             "IsNone():";
1963     code += GenIndents(3) + "self." + field_field + " = []";
1964     code += GenIndents(3) + "for i in range(" + struct_var + "." +
1965             field_method + "Length()):";
1966 
1967     auto field_type = TypeName(field);
1968     auto one_instance = field_type + "_";
1969     one_instance[0] = CharToLower(one_instance[0]);
1970     if (parser_.opts.include_dependence_headers) {
1971       auto package_reference = GenPackageReference(field.value.type);
1972       field_type = package_reference + "." + TypeName(field);
1973     }
1974     code += GenIndents(4) + "if " + struct_var + "." + field_method +
1975             "(i) is None:";
1976     code += GenIndents(5) + "self." + field_field + ".append(None)";
1977     code += GenIndents(4) + "else:";
1978     code += GenIndents(5) + one_instance + " = " +
1979             namer_.ObjectType(field_type) + ".InitFromObj(" + struct_var + "." +
1980             field_method + "(i))";
1981     code +=
1982         GenIndents(5) + "self." + field_field + ".append(" + one_instance + ")";
1983   }
1984 
GenUnpackforScalarVectorHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents) const1985   void GenUnpackforScalarVectorHelper(const StructDef &struct_def,
1986                                       const FieldDef &field,
1987                                       std::string *code_ptr,
1988                                       int indents) const {
1989     auto &code = *code_ptr;
1990     const auto field_field = namer_.Field(field);
1991     const auto field_method = namer_.Method(field);
1992     const auto struct_var = namer_.Variable(struct_def);
1993 
1994     code += GenIndents(indents) + "self." + field_field + " = []";
1995     code += GenIndents(indents) + "for i in range(" + struct_var + "." +
1996             field_method + "Length()):";
1997     code += GenIndents(indents + 1) + "self." + field_field + ".append(" +
1998             struct_var + "." + field_method + "(i))";
1999   }
2000 
GenUnPackForScalarVector(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const2001   void GenUnPackForScalarVector(const StructDef &struct_def,
2002                                 const FieldDef &field,
2003                                 std::string *code_ptr) const {
2004     auto &code = *code_ptr;
2005     const auto field_field = namer_.Field(field);
2006     const auto field_method = namer_.Method(field);
2007     const auto struct_var = namer_.Variable(struct_def);
2008 
2009     code += GenIndents(2) + "if not " + struct_var + "." + field_method +
2010             "IsNone():";
2011 
2012     // String does not have the AsNumpy method.
2013     if (!(IsScalar(field.value.type.VectorType().base_type))) {
2014       GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
2015       return;
2016     }
2017 
2018     if (parser_.opts.python_gen_numpy) {
2019       code += GenIndents(3) + "if np is None:";
2020       GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 4);
2021 
2022       // If numpy exists, use the AsNumpy method to optimize the unpack speed.
2023       code += GenIndents(3) + "else:";
2024       code += GenIndents(4) + "self." + field_field + " = " + struct_var + "." +
2025               field_method + "AsNumpy()";
2026     } else {
2027       GenUnpackforScalarVectorHelper(struct_def, field, code_ptr, 3);
2028     }
2029   }
2030 
GenUnPackForScalar(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr) const2031   void GenUnPackForScalar(const StructDef &struct_def, const FieldDef &field,
2032                           std::string *code_ptr) const {
2033     auto &code = *code_ptr;
2034     const auto field_field = namer_.Field(field);
2035     const auto field_method = namer_.Method(field);
2036     const auto struct_var = namer_.Variable(struct_def);
2037 
2038     code += GenIndents(2) + "self." + field_field + " = " + struct_var + "." +
2039             field_method + "()";
2040   }
2041 
2042   // Generates the UnPack method for the object class.
GenUnPack(const StructDef & struct_def,std::string * code_ptr) const2043   void GenUnPack(const StructDef &struct_def, std::string *code_ptr) const {
2044     std::string code;
2045     // Items that needs to be imported. No duplicate modules will be imported.
2046     std::set<std::string> import_list;
2047 
2048     for (auto it = struct_def.fields.vec.begin();
2049          it != struct_def.fields.vec.end(); ++it) {
2050       auto &field = **it;
2051       if (field.deprecated) continue;
2052 
2053       auto field_type = TypeName(field);
2054       switch (field.value.type.base_type) {
2055         case BASE_TYPE_STRUCT: {
2056           GenUnPackForStruct(struct_def, field, &code);
2057           break;
2058         }
2059         case BASE_TYPE_UNION: {
2060           GenUnPackForUnion(struct_def, field, &code);
2061           break;
2062         }
2063         case BASE_TYPE_ARRAY:
2064         case BASE_TYPE_VECTOR: {
2065           auto vectortype = field.value.type.VectorType();
2066           if (vectortype.base_type == BASE_TYPE_STRUCT) {
2067             GenUnPackForStructVector(struct_def, field, &code);
2068           } else {
2069             GenUnPackForScalarVector(struct_def, field, &code);
2070           }
2071           break;
2072         }
2073         default: GenUnPackForScalar(struct_def, field, &code);
2074       }
2075     }
2076 
2077     // Writes import statements and code into the generated file.
2078     auto &code_base = *code_ptr;
2079     const auto struct_var = namer_.Variable(struct_def);
2080 
2081     GenReceiverForObjectAPI(struct_def, code_ptr);
2082     code_base += "_UnPack(self, " + struct_var + "):";
2083     code_base += GenIndents(2) + "if " + struct_var + " is None:";
2084     code_base += GenIndents(3) + "return";
2085 
2086     // Write the import statements.
2087     for (std::set<std::string>::iterator it = import_list.begin();
2088          it != import_list.end(); ++it) {
2089       code_base += GenIndents(2) + *it;
2090     }
2091 
2092     // Write the code.
2093     code_base += code;
2094     code_base += "\n";
2095   }
2096 
GenPackForStruct(const StructDef & struct_def,std::string * code_ptr) const2097   void GenPackForStruct(const StructDef &struct_def,
2098                         std::string *code_ptr) const {
2099     auto &code = *code_ptr;
2100     const auto struct_fn = namer_.Function(struct_def);
2101 
2102     GenReceiverForObjectAPI(struct_def, code_ptr);
2103     code += "Pack(self, builder):";
2104     code += GenIndents(2) + "return Create" + struct_fn + "(builder";
2105 
2106     StructBuilderArgs(struct_def,
2107                       /* nameprefix = */ "self.",
2108                       /* namesuffix = */ "",
2109                       /* has_field_name = */ true,
2110                       /* fieldname_suffix = */ ".", code_ptr);
2111     code += ")\n";
2112   }
2113 
GenPackForStructVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr) const2114   void GenPackForStructVectorField(const StructDef &struct_def,
2115                                    const FieldDef &field,
2116                                    std::string *code_prefix_ptr,
2117                                    std::string *code_ptr) const {
2118     auto &code_prefix = *code_prefix_ptr;
2119     auto &code = *code_ptr;
2120     const auto field_field = namer_.Field(field);
2121     const auto struct_type = namer_.Type(struct_def);
2122     const auto field_method = namer_.Method(field);
2123 
2124     // Creates the field.
2125     code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
2126     if (field.value.type.struct_def->fixed) {
2127       code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
2128                      "Vector(builder, len(self." + field_field + "))";
2129       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
2130                      field_field + "))):";
2131       code_prefix +=
2132           GenIndents(4) + "self." + field_field + "[i].Pack(builder)";
2133       code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
2134     } else {
2135       // If the vector is a struct vector, we need to first build accessor for
2136       // each struct element.
2137       code_prefix += GenIndents(3) + field_field + "list = []";
2138       code_prefix += GenIndents(3);
2139       code_prefix += "for i in range(len(self." + field_field + ")):";
2140       code_prefix += GenIndents(4) + field_field + "list.append(self." +
2141                      field_field + "[i].Pack(builder))";
2142 
2143       code_prefix += GenIndents(3) + struct_type + "Start" + field_method +
2144                      "Vector(builder, len(self." + field_field + "))";
2145       code_prefix += GenIndents(3) + "for i in reversed(range(len(self." +
2146                      field_field + "))):";
2147       code_prefix += GenIndents(4) + "builder.PrependUOffsetTRelative" + "(" +
2148                      field_field + "list[i])";
2149       code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
2150     }
2151 
2152     // Adds the field into the struct.
2153     code += GenIndents(2) + "if self." + field_field + " is not None:";
2154     code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
2155             field_field + ")";
2156   }
2157 
GenPackForScalarVectorFieldHelper(const StructDef & struct_def,const FieldDef & field,std::string * code_ptr,int indents) const2158   void GenPackForScalarVectorFieldHelper(const StructDef &struct_def,
2159                                          const FieldDef &field,
2160                                          std::string *code_ptr,
2161                                          int indents) const {
2162     auto &code = *code_ptr;
2163     const auto field_field = namer_.Field(field);
2164     const auto field_method = namer_.Method(field);
2165     const auto struct_type = namer_.Type(struct_def);
2166     const auto vectortype = field.value.type.VectorType();
2167 
2168     code += GenIndents(indents) + struct_type + "Start" + field_method +
2169             "Vector(builder, len(self." + field_field + "))";
2170     code += GenIndents(indents) + "for i in reversed(range(len(self." +
2171             field_field + "))):";
2172     code += GenIndents(indents + 1) + "builder.Prepend";
2173 
2174     std::string type_name;
2175     switch (vectortype.base_type) {
2176       case BASE_TYPE_BOOL: type_name = "Bool"; break;
2177       case BASE_TYPE_CHAR: type_name = "Byte"; break;
2178       case BASE_TYPE_UCHAR: type_name = "Uint8"; break;
2179       case BASE_TYPE_SHORT: type_name = "Int16"; break;
2180       case BASE_TYPE_USHORT: type_name = "Uint16"; break;
2181       case BASE_TYPE_INT: type_name = "Int32"; break;
2182       case BASE_TYPE_UINT: type_name = "Uint32"; break;
2183       case BASE_TYPE_LONG: type_name = "Int64"; break;
2184       case BASE_TYPE_ULONG: type_name = "Uint64"; break;
2185       case BASE_TYPE_FLOAT: type_name = "Float32"; break;
2186       case BASE_TYPE_DOUBLE: type_name = "Float64"; break;
2187       case BASE_TYPE_STRING: type_name = "UOffsetTRelative"; break;
2188       default: type_name = "VOffsetT"; break;
2189     }
2190     code += type_name;
2191   }
2192 
GenPackForScalarVectorField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr) const2193   void GenPackForScalarVectorField(const StructDef &struct_def,
2194                                    const FieldDef &field,
2195                                    std::string *code_prefix_ptr,
2196                                    std::string *code_ptr) const {
2197     auto &code = *code_ptr;
2198     auto &code_prefix = *code_prefix_ptr;
2199     const auto field_field = namer_.Field(field);
2200     const auto field_method = namer_.Method(field);
2201     const auto struct_type = namer_.Type(struct_def);
2202 
2203     // Adds the field into the struct.
2204     code += GenIndents(2) + "if self." + field_field + " is not None:";
2205     code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
2206             field_field + ")";
2207 
2208     // Creates the field.
2209     code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
2210     // If the vector is a string vector, we need to first build accessor for
2211     // each string element. And this generated code, needs to be
2212     // placed ahead of code_prefix.
2213     auto vectortype = field.value.type.VectorType();
2214     if (IsString(vectortype)) {
2215       code_prefix += GenIndents(3) + field_field + "list = []";
2216       code_prefix +=
2217           GenIndents(3) + "for i in range(len(self." + field_field + ")):";
2218       code_prefix += GenIndents(4) + field_field +
2219                      "list.append(builder.CreateString(self." + field_field +
2220                      "[i]))";
2221       GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
2222       code_prefix += "(" + field_field + "list[i])";
2223       code_prefix += GenIndents(3) + field_field + " = builder.EndVector()";
2224       return;
2225     }
2226 
2227     if (parser_.opts.python_gen_numpy) {
2228       code_prefix += GenIndents(3) + "if np is not None and type(self." +
2229                     field_field + ") is np.ndarray:";
2230       code_prefix += GenIndents(4) + field_field +
2231                     " = builder.CreateNumpyVector(self." + field_field + ")";
2232       code_prefix += GenIndents(3) + "else:";
2233       GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 4);
2234       code_prefix += "(self." + field_field + "[i])";
2235       code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
2236     } else {
2237       GenPackForScalarVectorFieldHelper(struct_def, field, code_prefix_ptr, 3);
2238       code_prefix += "(self." + field_field + "[i])";
2239       code_prefix += GenIndents(4) + field_field + " = builder.EndVector()";
2240     }
2241   }
2242 
GenPackForStructField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr) const2243   void GenPackForStructField(const StructDef &struct_def, const FieldDef &field,
2244                              std::string *code_prefix_ptr,
2245                              std::string *code_ptr) const {
2246     auto &code_prefix = *code_prefix_ptr;
2247     auto &code = *code_ptr;
2248     const auto field_field = namer_.Field(field);
2249     const auto field_method = namer_.Method(field);
2250     const auto struct_type = namer_.Type(struct_def);
2251 
2252     if (field.value.type.struct_def->fixed) {
2253       // Pure struct fields need to be created along with their parent
2254       // structs.
2255       code += GenIndents(2) + "if self." + field_field + " is not None:";
2256       code += GenIndents(3) + field_field + " = self." + field_field +
2257               ".Pack(builder)";
2258     } else {
2259       // Tables need to be created before their parent structs are created.
2260       code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
2261       code_prefix += GenIndents(3) + field_field + " = self." + field_field +
2262                      ".Pack(builder)";
2263       code += GenIndents(2) + "if self." + field_field + " is not None:";
2264     }
2265 
2266     code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
2267             field_field + ")";
2268   }
2269 
GenPackForUnionField(const StructDef & struct_def,const FieldDef & field,std::string * code_prefix_ptr,std::string * code_ptr) const2270   void GenPackForUnionField(const StructDef &struct_def, const FieldDef &field,
2271                             std::string *code_prefix_ptr,
2272                             std::string *code_ptr) const {
2273     auto &code_prefix = *code_prefix_ptr;
2274     auto &code = *code_ptr;
2275     const auto field_field = namer_.Field(field);
2276     const auto field_method = namer_.Method(field);
2277     const auto struct_type = namer_.Type(struct_def);
2278 
2279     // TODO(luwa): TypeT should be moved under the None check as well.
2280     code_prefix += GenIndents(2) + "if self." + field_field + " is not None:";
2281     code_prefix += GenIndents(3) + field_field + " = self." + field_field +
2282                    ".Pack(builder)";
2283     code += GenIndents(2) + "if self." + field_field + " is not None:";
2284     code += GenIndents(3) + struct_type + "Add" + field_method + "(builder, " +
2285             field_field + ")";
2286   }
2287 
GenPackForTable(const StructDef & struct_def,std::string * code_ptr) const2288   void GenPackForTable(const StructDef &struct_def,
2289                        std::string *code_ptr) const {
2290     auto &code_base = *code_ptr;
2291     std::string code, code_prefix;
2292     const auto struct_var = namer_.Variable(struct_def);
2293     const auto struct_type = namer_.Type(struct_def);
2294 
2295     GenReceiverForObjectAPI(struct_def, code_ptr);
2296     code_base += "Pack(self, builder):";
2297     code += GenIndents(2) + struct_type + "Start(builder)";
2298     for (auto it = struct_def.fields.vec.begin();
2299          it != struct_def.fields.vec.end(); ++it) {
2300       auto &field = **it;
2301       if (field.deprecated) continue;
2302 
2303       const auto field_method = namer_.Method(field);
2304       const auto field_field = namer_.Field(field);
2305 
2306       switch (field.value.type.base_type) {
2307         case BASE_TYPE_STRUCT: {
2308           GenPackForStructField(struct_def, field, &code_prefix, &code);
2309           break;
2310         }
2311         case BASE_TYPE_UNION: {
2312           GenPackForUnionField(struct_def, field, &code_prefix, &code);
2313           break;
2314         }
2315         case BASE_TYPE_ARRAY:
2316         case BASE_TYPE_VECTOR: {
2317           auto vectortype = field.value.type.VectorType();
2318           if (vectortype.base_type == BASE_TYPE_STRUCT) {
2319             GenPackForStructVectorField(struct_def, field, &code_prefix, &code);
2320           } else {
2321             GenPackForScalarVectorField(struct_def, field, &code_prefix, &code);
2322           }
2323           break;
2324         }
2325         case BASE_TYPE_STRING: {
2326           code_prefix +=
2327               GenIndents(2) + "if self." + field_field + " is not None:";
2328           code_prefix += GenIndents(3) + field_field +
2329                          " = builder.CreateString(self." + field_field + ")";
2330           code += GenIndents(2) + "if self." + field_field + " is not None:";
2331           code += GenIndents(3) + struct_type + "Add" + field_method +
2332                   "(builder, " + field_field + ")";
2333           break;
2334         }
2335         default:
2336           // Generates code for scalar values. If the value equals to the
2337           // default value, builder will automatically ignore it. So we don't
2338           // need to check the value ahead.
2339           code += GenIndents(2) + struct_type + "Add" + field_method +
2340                   "(builder, self." + field_field + ")";
2341           break;
2342       }
2343     }
2344 
2345     code += GenIndents(2) + struct_var + " = " + struct_type + "End(builder)";
2346     code += GenIndents(2) + "return " + struct_var;
2347 
2348     code_base += code_prefix + code;
2349     code_base += "\n";
2350   }
2351 
GenStructForObjectAPI(const StructDef & struct_def,std::string * code_ptr) const2352   void GenStructForObjectAPI(const StructDef &struct_def,
2353                              std::string *code_ptr) const {
2354     if (struct_def.generated) return;
2355 
2356     std::set<std::string> import_list;
2357     std::string code;
2358 
2359     // Creates an object class for a struct or a table
2360     BeginClassForObjectAPI(struct_def, &code);
2361 
2362     GenInitialize(struct_def, &code, &import_list);
2363 
2364     InitializeFromBuf(struct_def, &code);
2365 
2366     InitializeFromPackedBuf(struct_def, &code);
2367 
2368     InitializeFromObjForObject(struct_def, &code);
2369 
2370     if (parser_.opts.gen_compare) { GenCompareOperator(struct_def, &code); }
2371 
2372     GenUnPack(struct_def, &code);
2373 
2374     if (struct_def.fixed) {
2375       GenPackForStruct(struct_def, &code);
2376     } else {
2377       GenPackForTable(struct_def, &code);
2378     }
2379 
2380     // Adds the imports at top.
2381     auto &code_base = *code_ptr;
2382     code_base += "\n";
2383     for (auto it = import_list.begin(); it != import_list.end(); it++) {
2384       auto im = *it;
2385       code_base += im + "\n";
2386     }
2387     code_base += code;
2388   }
2389 
GenUnionCreatorForStruct(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr) const2390   void GenUnionCreatorForStruct(const EnumDef &enum_def, const EnumVal &ev,
2391                                 std::string *code_ptr) const {
2392     auto &code = *code_ptr;
2393     const auto union_type = namer_.Type(enum_def);
2394     const auto variant = namer_.Variant(ev);
2395     auto field_type = namer_.ObjectType(*ev.union_type.struct_def);
2396 
2397     code +=
2398         GenIndents(1) + "if unionType == " + union_type + "." + variant + ":";
2399     if (parser_.opts.include_dependence_headers) {
2400       auto package_reference = GenPackageReference(ev.union_type);
2401       code += GenIndents(2) + "import " + package_reference;
2402       field_type = package_reference + "." + field_type;
2403     }
2404     code += GenIndents(2) + "return " + field_type +
2405             ".InitFromBuf(table.Bytes, table.Pos)";
2406   }
2407 
GenUnionCreatorForString(const EnumDef & enum_def,const EnumVal & ev,std::string * code_ptr) const2408   void GenUnionCreatorForString(const EnumDef &enum_def, const EnumVal &ev,
2409                                 std::string *code_ptr) const {
2410     auto &code = *code_ptr;
2411     const auto union_type = namer_.Type(enum_def);
2412     const auto variant = namer_.Variant(ev);
2413 
2414     code +=
2415         GenIndents(1) + "if unionType == " + union_type + "()." + variant + ":";
2416     code += GenIndents(2) + "tab = Table(table.Bytes, table.Pos)";
2417     code += GenIndents(2) + "union = tab.String(table.Pos)";
2418     code += GenIndents(2) + "return union";
2419   }
2420 
2421   // Creates an union object based on union type.
GenUnionCreator(const EnumDef & enum_def,std::string * code_ptr) const2422   void GenUnionCreator(const EnumDef &enum_def, std::string *code_ptr) const {
2423     if (enum_def.generated) return;
2424 
2425     auto &code = *code_ptr;
2426     const auto enum_fn = namer_.Function(enum_def);
2427 
2428     code += "\n";
2429     code += "def " + enum_fn + "Creator(unionType, table):";
2430     code += GenIndents(1) + "from flatbuffers.table import Table";
2431     code += GenIndents(1) + "if not isinstance(table, Table):";
2432     code += GenIndents(2) + "return None";
2433 
2434     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
2435       auto &ev = **it;
2436       // Union only supports string and table.
2437       switch (ev.union_type.base_type) {
2438         case BASE_TYPE_STRUCT:
2439           GenUnionCreatorForStruct(enum_def, ev, &code);
2440           break;
2441         case BASE_TYPE_STRING:
2442           GenUnionCreatorForString(enum_def, ev, &code);
2443           break;
2444         default: break;
2445       }
2446     }
2447     code += GenIndents(1) + "return None";
2448     code += "\n";
2449   }
2450 
2451   // Generate enum declarations.
GenEnum(const EnumDef & enum_def,std::string * code_ptr) const2452   void GenEnum(const EnumDef &enum_def, std::string *code_ptr) const {
2453     if (enum_def.generated) return;
2454 
2455     GenComment(enum_def.doc_comment, code_ptr, &def_comment);
2456     BeginEnum(enum_def, code_ptr);
2457     for (auto it = enum_def.Vals().begin(); it != enum_def.Vals().end(); ++it) {
2458       auto &ev = **it;
2459       GenComment(ev.doc_comment, code_ptr, &def_comment, Indent.c_str());
2460       EnumMember(enum_def, ev, code_ptr);
2461     }
2462   }
2463 
2464   // Returns the function name that is able to read a value of the given type.
GenGetter(const Type & type) const2465   std::string GenGetter(const Type &type) const {
2466     switch (type.base_type) {
2467       case BASE_TYPE_STRING: return "self._tab.String(";
2468       case BASE_TYPE_UNION: return "self._tab.Union(";
2469       case BASE_TYPE_VECTOR: return GenGetter(type.VectorType());
2470       default:
2471         return "self._tab.Get(flatbuffers.number_types." +
2472                namer_.Method(GenTypeGet(type)) + "Flags, ";
2473     }
2474   }
2475 
GenFieldTy(const FieldDef & field) const2476   std::string GenFieldTy(const FieldDef &field) const {
2477     if (IsScalar(field.value.type.base_type) || IsArray(field.value.type)) {
2478       const std::string ty = GenTypeBasic(field.value.type);
2479       if (ty.find("int") != std::string::npos) { return "int"; }
2480 
2481       if (ty.find("float") != std::string::npos) { return "float"; }
2482 
2483       if (ty == "bool") { return "bool"; }
2484 
2485       return "Any";
2486     } else {
2487       if (IsStruct(field.value.type)) {
2488         return "Any";
2489       } else {
2490         return "int";
2491       }
2492     }
2493   }
2494 
2495   // Returns the method name for use with add/put calls.
GenMethod(const FieldDef & field) const2496   std::string GenMethod(const FieldDef &field) const {
2497     return (IsScalar(field.value.type.base_type) || IsArray(field.value.type))
2498                ? namer_.Method(GenTypeBasic(field.value.type))
2499                : (IsStruct(field.value.type) ? "Struct" : "UOffsetTRelative");
2500   }
2501 
GenTypeBasic(const Type & type) const2502   std::string GenTypeBasic(const Type &type) const {
2503     // clang-format off
2504     static const char *ctypename[] = {
2505       #define FLATBUFFERS_TD(ENUM, IDLTYPE, \
2506               CTYPE, JTYPE, GTYPE, NTYPE, PTYPE, ...) \
2507         #PTYPE,
2508         FLATBUFFERS_GEN_TYPES(FLATBUFFERS_TD)
2509       #undef FLATBUFFERS_TD
2510     };
2511     // clang-format on
2512     return ctypename[IsArray(type) ? type.VectorType().base_type
2513                                    : type.base_type];
2514   }
2515 
GenTypePointer(const Type & type) const2516   std::string GenTypePointer(const Type &type) const {
2517     switch (type.base_type) {
2518       case BASE_TYPE_STRING: return "string";
2519       case BASE_TYPE_VECTOR:
2520         // fall through
2521       case BASE_TYPE_ARRAY: return GenTypeGet(type.VectorType());
2522       case BASE_TYPE_STRUCT: return type.struct_def->name;
2523       case BASE_TYPE_UNION:
2524         // fall through
2525       default: return "*flatbuffers.Table";
2526     }
2527   }
2528 
GenTypeGet(const Type & type) const2529   std::string GenTypeGet(const Type &type) const {
2530     return IsScalar(type.base_type) ? GenTypeBasic(type) : GenTypePointer(type);
2531   }
2532 
TypeName(const FieldDef & field) const2533   std::string TypeName(const FieldDef &field) const {
2534     return GenTypeGet(field.value.type);
2535   }
2536 
ReturnType(const StructDef & struct_def,const FieldDef & field) const2537   std::string ReturnType(const StructDef &struct_def,
2538                          const FieldDef &field) const {
2539     // If we have a class member that returns an instance of the same class,
2540     // for example:
2541     // class Field(object):
2542     //   def Children(self, j: int) -> Optional[Field]:
2543     //     pass
2544     //
2545     // we need to quote the return type:
2546     // class Field(object):
2547     //   def Children(self, j: int) -> Optional['Field']:
2548     //     pass
2549     //
2550     // because Python is unable to resolve the name during parse and will return
2551     // an error.
2552     // (see PEP 484 under forward references:
2553     // https://peps.python.org/pep-0484/#forward-references)
2554     const std::string self_type = struct_def.name;
2555     std::string field_type = TypeName(field);
2556 
2557     if (self_type == field_type) { field_type = "'" + field_type + "'"; }
2558 
2559     return field_type;
2560   }
2561 
2562   // Create a struct with a builder and the struct's arguments.
GenStructBuilder(const StructDef & struct_def,std::string * code_ptr) const2563   void GenStructBuilder(const StructDef &struct_def,
2564                         std::string *code_ptr) const {
2565     BeginBuilderArgs(struct_def, code_ptr);
2566     StructBuilderArgs(struct_def,
2567                       /* nameprefix = */ "",
2568                       /* namesuffix = */ "",
2569                       /* has_field_name = */ true,
2570                       /* fieldname_suffix = */ "_", code_ptr);
2571     EndBuilderArgs(code_ptr);
2572 
2573     StructBuilderBody(struct_def, "", code_ptr);
2574     EndBuilderBody(code_ptr);
2575   }
2576 
generate()2577   bool generate() {
2578     std::string one_file_code;
2579     ImportMap one_file_imports;
2580     if (!generateEnums(&one_file_code)) return false;
2581     if (!generateStructs(&one_file_code, one_file_imports)) return false;
2582 
2583     if (parser_.opts.one_file) {
2584       const std::string mod = file_name_ + parser_.opts.filename_suffix;
2585 
2586       // Legacy file format uses keep casing.
2587       return SaveType(mod + ".py", *parser_.current_namespace_, one_file_code,
2588                       one_file_imports, mod, true);
2589     }
2590 
2591     return true;
2592   }
2593 
2594  private:
generateEnums(std::string * one_file_code) const2595   bool generateEnums(std::string *one_file_code) const {
2596     for (auto it = parser_.enums_.vec.begin(); it != parser_.enums_.vec.end();
2597          ++it) {
2598       auto &enum_def = **it;
2599       std::string enumcode;
2600       GenEnum(enum_def, &enumcode);
2601       if (parser_.opts.generate_object_based_api & enum_def.is_union) {
2602         GenUnionCreator(enum_def, &enumcode);
2603       }
2604 
2605       if (parser_.opts.one_file && !enumcode.empty()) {
2606         *one_file_code += enumcode + "\n\n";
2607       } else {
2608         ImportMap imports;
2609         const std::string mod =
2610             namer_.File(enum_def, SkipFile::SuffixAndExtension);
2611 
2612         if (!SaveType(namer_.File(enum_def, SkipFile::Suffix),
2613                       *enum_def.defined_namespace, enumcode, imports, mod,
2614                       false))
2615           return false;
2616       }
2617     }
2618     return true;
2619   }
2620 
generateStructs(std::string * one_file_code,ImportMap & one_file_imports) const2621   bool generateStructs(std::string *one_file_code,
2622                        ImportMap &one_file_imports) const {
2623     for (auto it = parser_.structs_.vec.begin();
2624          it != parser_.structs_.vec.end(); ++it) {
2625       auto &struct_def = **it;
2626       std::string declcode;
2627       ImportMap imports;
2628       GenStruct(struct_def, &declcode, imports);
2629       if (parser_.opts.generate_object_based_api) {
2630         GenStructForObjectAPI(struct_def, &declcode);
2631       }
2632 
2633       if (parser_.opts.one_file) {
2634         if (!declcode.empty()) { *one_file_code += declcode + "\n\n"; }
2635 
2636         for (auto import_str : imports) { one_file_imports.insert(import_str); }
2637       } else {
2638         const std::string mod =
2639             namer_.File(struct_def, SkipFile::SuffixAndExtension);
2640         if (!SaveType(namer_.File(struct_def, SkipFile::Suffix),
2641                       *struct_def.defined_namespace, declcode, imports, mod,
2642                       true))
2643           return false;
2644       }
2645     }
2646     return true;
2647   }
2648 
2649   // Begin by declaring namespace and imports.
BeginFile(const std::string & name_space_name,const bool needs_imports,std::string * code_ptr,const std::string & mod,const ImportMap & imports) const2650   void BeginFile(const std::string &name_space_name, const bool needs_imports,
2651                  std::string *code_ptr, const std::string &mod,
2652                  const ImportMap &imports) const {
2653     auto &code = *code_ptr;
2654     code = code + "# " + FlatBuffersGeneratedWarning() + "\n\n";
2655     code += "# namespace: " + name_space_name + "\n\n";
2656 
2657     if (needs_imports) {
2658       const std::string local_import = "." + mod;
2659 
2660       code += "import flatbuffers\n";
2661       if (parser_.opts.python_gen_numpy) {
2662         code += "from flatbuffers.compat import import_numpy\n";
2663       }
2664       if (parser_.opts.python_typing) {
2665         code += "from typing import Any\n";
2666 
2667         for (auto import_entry : imports) {
2668           // If we have a file called, say, "MyType.py" and in it we have a
2669           // class "MyType", we can generate imports -- usually when we
2670           // have a type that contains arrays of itself -- of the type
2671           // "from .MyType import MyType", which Python can't resolve. So
2672           // if we are trying to import ourself, we skip.
2673           if (import_entry.first != local_import) {
2674             code += "from " + import_entry.first + " import " +
2675                     import_entry.second + "\n";
2676           }
2677         }
2678       }
2679       if (parser_.opts.python_gen_numpy) {
2680         code += "np = import_numpy()\n\n";
2681       }
2682     }
2683   }
2684 
2685   // Save out the generated code for a Python Table type.
SaveType(const std::string & defname,const Namespace & ns,const std::string & classcode,const ImportMap & imports,const std::string & mod,bool needs_imports) const2686   bool SaveType(const std::string &defname, const Namespace &ns,
2687                 const std::string &classcode, const ImportMap &imports,
2688                 const std::string &mod, bool needs_imports) const {
2689     std::string code = "";
2690     if (classcode.empty()) {
2691       BeginFile(LastNamespacePart(ns), false, &code, "", {});
2692       code += "# NOTE " + defname + " does not declare any structs or enums\n";
2693     } else {
2694       BeginFile(LastNamespacePart(ns), needs_imports, &code, mod, imports);
2695       code += classcode;
2696     }
2697 
2698     const std::string directories =
2699         parser_.opts.one_file ? path_ : namer_.Directories(ns.components);
2700     EnsureDirExists(directories);
2701 
2702     for (size_t i = path_.size() + 1; i != std::string::npos;
2703          i = directories.find(kPathSeparator, i + 1)) {
2704       const std::string init_py =
2705           directories.substr(0, i) + kPathSeparator + "__init__.py";
2706       SaveFile(init_py.c_str(), "", false);
2707     }
2708 
2709     const std::string filename = directories + defname;
2710     return SaveFile(filename.c_str(), code, false);
2711   }
2712 
2713  private:
2714   const SimpleFloatConstantGenerator float_const_gen_;
2715   const IdlNamer namer_;
2716 };
2717 
2718 }  // namespace python
2719 
GeneratePython(const Parser & parser,const std::string & path,const std::string & file_name)2720 static bool GeneratePython(const Parser &parser, const std::string &path,
2721                            const std::string &file_name) {
2722   python::Version version{parser.opts.python_version};
2723   if (!version.IsValid()) return false;
2724 
2725   python::PythonGenerator generator(parser, path, file_name, version);
2726   if (!generator.generate()) return false;
2727 
2728   if (parser.opts.python_typing) {
2729     python::PythonStubGenerator stub_generator(parser, path, version);
2730     if (!stub_generator.Generate()) return false;
2731   }
2732   return true;
2733 }
2734 
2735 namespace {
2736 
2737 class PythonCodeGenerator : public CodeGenerator {
2738  public:
GenerateCode(const Parser & parser,const std::string & path,const std::string & filename)2739   Status GenerateCode(const Parser &parser, const std::string &path,
2740                       const std::string &filename) override {
2741     if (!GeneratePython(parser, path, filename)) { return Status::ERROR; }
2742     return Status::OK;
2743   }
2744 
GenerateCode(const uint8_t *,int64_t,const CodeGenOptions &)2745   Status GenerateCode(const uint8_t *, int64_t,
2746                       const CodeGenOptions &) override {
2747     return Status::NOT_IMPLEMENTED;
2748   }
2749 
GenerateMakeRule(const Parser & parser,const std::string & path,const std::string & filename,std::string & output)2750   Status GenerateMakeRule(const Parser &parser, const std::string &path,
2751                           const std::string &filename,
2752                           std::string &output) override {
2753     (void)parser;
2754     (void)path;
2755     (void)filename;
2756     (void)output;
2757     return Status::NOT_IMPLEMENTED;
2758   }
2759 
GenerateGrpcCode(const Parser & parser,const std::string & path,const std::string & filename)2760   Status GenerateGrpcCode(const Parser &parser, const std::string &path,
2761                           const std::string &filename) override {
2762     if (!GeneratePythonGRPC(parser, path, filename)) { return Status::ERROR; }
2763     return Status::OK;
2764   }
2765 
GenerateRootFile(const Parser & parser,const std::string & path)2766   Status GenerateRootFile(const Parser &parser,
2767                           const std::string &path) override {
2768     (void)parser;
2769     (void)path;
2770     return Status::NOT_IMPLEMENTED;
2771   }
2772 
IsSchemaOnly() const2773   bool IsSchemaOnly() const override { return true; }
2774 
SupportsBfbsGeneration() const2775   bool SupportsBfbsGeneration() const override { return false; }
SupportsRootFileGeneration() const2776   bool SupportsRootFileGeneration() const override { return false; }
2777 
Language() const2778   IDLOptions::Language Language() const override { return IDLOptions::kPython; }
2779 
LanguageName() const2780   std::string LanguageName() const override { return "Python"; }
2781 };
2782 }  // namespace
2783 
NewPythonCodeGenerator()2784 std::unique_ptr<CodeGenerator> NewPythonCodeGenerator() {
2785   return std::unique_ptr<PythonCodeGenerator>(new PythonCodeGenerator());
2786 }
2787 
2788 }  // namespace flatbuffers
2789