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