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