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