forked from BigfootDev/flatbuffers
Generate code to encode and decode nested flatbuffers in Python. (#6354)
* Generate code to encode and decode nested flatbuffers in Python. * Delete accidental trailing whitespace. * Fully delete trailing whitespace.
This commit is contained in:
@@ -408,6 +408,39 @@ class PythonGenerator : public BaseGenerator {
|
|||||||
code += "\n";
|
code += "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Returns a nested flatbuffer as itself.
|
||||||
|
void GetVectorAsNestedFlatbuffer(const StructDef &struct_def,
|
||||||
|
const FieldDef &field,
|
||||||
|
std::string *code_ptr) {
|
||||||
|
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
||||||
|
if (!nested) { return; } // There is no nested flatbuffer.
|
||||||
|
|
||||||
|
std::string unqualified_name = nested->constant;
|
||||||
|
std::string qualified_name = nested->constant;
|
||||||
|
auto nested_root = parser_.LookupStruct(nested->constant);
|
||||||
|
if (nested_root == nullptr) {
|
||||||
|
qualified_name = parser_.current_namespace_->GetFullyQualifiedName(
|
||||||
|
nested->constant);
|
||||||
|
nested_root = parser_.LookupStruct(qualified_name);
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
|
||||||
|
(void)nested_root;
|
||||||
|
|
||||||
|
auto &code = *code_ptr;
|
||||||
|
GenReceiver(struct_def, code_ptr);
|
||||||
|
code += MakeCamel(NormalizedName(field)) + "NestedRoot(self):";
|
||||||
|
|
||||||
|
code += OffsetPrefix(field);
|
||||||
|
|
||||||
|
code += Indent + Indent + Indent;
|
||||||
|
code += "from " + qualified_name + " import " + unqualified_name + "\n";
|
||||||
|
code += Indent + Indent + Indent + "return " + unqualified_name;
|
||||||
|
code += ".GetRootAs" + unqualified_name;
|
||||||
|
code += "(self._tab.Bytes, self._tab.Vector(o))\n";
|
||||||
|
code += Indent + Indent + "return 0\n";
|
||||||
|
code += "\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Begin the creator function signature.
|
// Begin the creator function signature.
|
||||||
void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
|
void BeginBuilderArgs(const StructDef &struct_def, std::string *code_ptr) {
|
||||||
auto &code = *code_ptr;
|
auto &code = *code_ptr;
|
||||||
@@ -561,6 +594,43 @@ class PythonGenerator : public BaseGenerator {
|
|||||||
code += ")\n";
|
code += ")\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Set the value of one of the members of a table's vector and fills in the
|
||||||
|
// elements from a bytearray. This is for simplifying the use of nested
|
||||||
|
// flatbuffers.
|
||||||
|
void BuildVectorOfTableFromBytes(const StructDef &struct_def,
|
||||||
|
const FieldDef &field,
|
||||||
|
std::string *code_ptr) {
|
||||||
|
auto nested = field.attributes.Lookup("nested_flatbuffer");
|
||||||
|
if (!nested) { return; } // There is no nested flatbuffer.
|
||||||
|
|
||||||
|
std::string unqualified_name = nested->constant;
|
||||||
|
std::string qualified_name = nested->constant;
|
||||||
|
auto nested_root = parser_.LookupStruct(nested->constant);
|
||||||
|
if (nested_root == nullptr) {
|
||||||
|
qualified_name =
|
||||||
|
parser_.current_namespace_->GetFullyQualifiedName(nested->constant);
|
||||||
|
nested_root = parser_.LookupStruct(qualified_name);
|
||||||
|
}
|
||||||
|
FLATBUFFERS_ASSERT(nested_root); // Guaranteed to exist by parser.
|
||||||
|
(void)nested_root;
|
||||||
|
|
||||||
|
auto &code = *code_ptr;
|
||||||
|
code += "def " + NormalizedName(struct_def) + "Make";
|
||||||
|
code += MakeCamel(NormalizedName(field));
|
||||||
|
code += "VectorFromBytes(builder, bytes):\n";
|
||||||
|
code += Indent + "builder.StartVector(";
|
||||||
|
auto vector_type = field.value.type.VectorType();
|
||||||
|
auto alignment = InlineAlignment(vector_type);
|
||||||
|
auto elem_size = InlineSize(vector_type);
|
||||||
|
code += NumToString(elem_size);
|
||||||
|
code += ", len(bytes), " + NumToString(alignment);
|
||||||
|
code += ")\n";
|
||||||
|
code += Indent + "builder.head = builder.head - len(bytes)\n";
|
||||||
|
code += Indent + "builder.Bytes[builder.head : builder.head + len(bytes)]";
|
||||||
|
code += " = bytes\n";
|
||||||
|
code += Indent + "return builder.EndVector(len(bytes))\n";
|
||||||
|
}
|
||||||
|
|
||||||
// Get the offset of the end of a table.
|
// Get the offset of the end of a table.
|
||||||
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
|
void GetEndOffsetOnTable(const StructDef &struct_def, std::string *code_ptr) {
|
||||||
auto &code = *code_ptr;
|
auto &code = *code_ptr;
|
||||||
@@ -607,6 +677,7 @@ class PythonGenerator : public BaseGenerator {
|
|||||||
} else {
|
} else {
|
||||||
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
|
GetMemberOfVectorOfNonStruct(struct_def, field, code_ptr);
|
||||||
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
|
GetVectorOfNonStructAsNumpy(struct_def, field, code_ptr);
|
||||||
|
GetVectorAsNestedFlatbuffer(struct_def, field, code_ptr);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -643,6 +714,7 @@ class PythonGenerator : public BaseGenerator {
|
|||||||
BuildFieldOfTable(struct_def, field, offset, code_ptr);
|
BuildFieldOfTable(struct_def, field, offset, code_ptr);
|
||||||
if (IsVector(field.value.type)) {
|
if (IsVector(field.value.type)) {
|
||||||
BuildVectorOfTable(struct_def, field, code_ptr);
|
BuildVectorOfTable(struct_def, field, code_ptr);
|
||||||
|
BuildVectorOfTableFromBytes(struct_def, field, code_ptr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -205,6 +205,14 @@ class Monster(object):
|
|||||||
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Monster
|
||||||
|
def TestnestedflatbufferNestedRoot(self):
|
||||||
|
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
|
||||||
|
if o != 0:
|
||||||
|
from MyGame.Example.Monster import Monster
|
||||||
|
return Monster.GetRootAsMonster(self._tab.Bytes, self._tab.Vector(o))
|
||||||
|
return 0
|
||||||
|
|
||||||
# Monster
|
# Monster
|
||||||
def TestnestedflatbufferLength(self):
|
def TestnestedflatbufferLength(self):
|
||||||
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
|
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(30))
|
||||||
@@ -734,6 +742,14 @@ class Monster(object):
|
|||||||
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
return self._tab.GetVectorAsNumpy(flatbuffers.number_types.Uint8Flags, o)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
# Monster
|
||||||
|
def TestrequirednestedflatbufferNestedRoot(self):
|
||||||
|
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(102))
|
||||||
|
if o != 0:
|
||||||
|
from MyGame.Example.Monster import Monster
|
||||||
|
return Monster.GetRootAsMonster(self._tab.Bytes, self._tab.Vector(o))
|
||||||
|
return 0
|
||||||
|
|
||||||
# Monster
|
# Monster
|
||||||
def TestrequirednestedflatbufferLength(self):
|
def TestrequirednestedflatbufferLength(self):
|
||||||
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(102))
|
o = flatbuffers.number_types.UOffsetTFlags.py_type(self._tab.Offset(102))
|
||||||
@@ -765,6 +781,11 @@ def MonsterStartTestarrayoftablesVector(builder, numElems): return builder.Start
|
|||||||
def MonsterAddEnemy(builder, enemy): builder.PrependUOffsetTRelativeSlot(12, flatbuffers.number_types.UOffsetTFlags.py_type(enemy), 0)
|
def MonsterAddEnemy(builder, enemy): builder.PrependUOffsetTRelativeSlot(12, flatbuffers.number_types.UOffsetTFlags.py_type(enemy), 0)
|
||||||
def MonsterAddTestnestedflatbuffer(builder, testnestedflatbuffer): builder.PrependUOffsetTRelativeSlot(13, flatbuffers.number_types.UOffsetTFlags.py_type(testnestedflatbuffer), 0)
|
def MonsterAddTestnestedflatbuffer(builder, testnestedflatbuffer): builder.PrependUOffsetTRelativeSlot(13, flatbuffers.number_types.UOffsetTFlags.py_type(testnestedflatbuffer), 0)
|
||||||
def MonsterStartTestnestedflatbufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
def MonsterStartTestnestedflatbufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
||||||
|
def MonsterMakeTestnestedflatbufferVectorFromBytes(builder, bytes):
|
||||||
|
builder.StartVector(1, len(bytes), 1)
|
||||||
|
builder.head = builder.head - len(bytes)
|
||||||
|
builder.Bytes[builder.head : builder.head + len(bytes)] = bytes
|
||||||
|
return builder.EndVector(len(bytes))
|
||||||
def MonsterAddTestempty(builder, testempty): builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(testempty), 0)
|
def MonsterAddTestempty(builder, testempty): builder.PrependUOffsetTRelativeSlot(14, flatbuffers.number_types.UOffsetTFlags.py_type(testempty), 0)
|
||||||
def MonsterAddTestbool(builder, testbool): builder.PrependBoolSlot(15, testbool, 0)
|
def MonsterAddTestbool(builder, testbool): builder.PrependBoolSlot(15, testbool, 0)
|
||||||
def MonsterAddTesthashs32Fnv1(builder, testhashs32Fnv1): builder.PrependInt32Slot(16, testhashs32Fnv1, 0)
|
def MonsterAddTesthashs32Fnv1(builder, testhashs32Fnv1): builder.PrependInt32Slot(16, testhashs32Fnv1, 0)
|
||||||
@@ -815,6 +836,11 @@ def MonsterStartVectorOfEnumsVector(builder, numElems): return builder.StartVect
|
|||||||
def MonsterAddSignedEnum(builder, signedEnum): builder.PrependInt8Slot(48, signedEnum, -1)
|
def MonsterAddSignedEnum(builder, signedEnum): builder.PrependInt8Slot(48, signedEnum, -1)
|
||||||
def MonsterAddTestrequirednestedflatbuffer(builder, testrequirednestedflatbuffer): builder.PrependUOffsetTRelativeSlot(49, flatbuffers.number_types.UOffsetTFlags.py_type(testrequirednestedflatbuffer), 0)
|
def MonsterAddTestrequirednestedflatbuffer(builder, testrequirednestedflatbuffer): builder.PrependUOffsetTRelativeSlot(49, flatbuffers.number_types.UOffsetTFlags.py_type(testrequirednestedflatbuffer), 0)
|
||||||
def MonsterStartTestrequirednestedflatbufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
def MonsterStartTestrequirednestedflatbufferVector(builder, numElems): return builder.StartVector(1, numElems, 1)
|
||||||
|
def MonsterMakeTestrequirednestedflatbufferVectorFromBytes(builder, bytes):
|
||||||
|
builder.StartVector(1, len(bytes), 1)
|
||||||
|
builder.head = builder.head - len(bytes)
|
||||||
|
builder.Bytes[builder.head : builder.head + len(bytes)] = bytes
|
||||||
|
return builder.EndVector(len(bytes))
|
||||||
def MonsterEnd(builder): return builder.EndObject()
|
def MonsterEnd(builder): return builder.EndObject()
|
||||||
|
|
||||||
import MyGame.Example.Ability
|
import MyGame.Example.Ability
|
||||||
|
|||||||
@@ -1874,6 +1874,35 @@ class TestAllCodePathsOfExampleSchema(unittest.TestCase):
|
|||||||
lambda: mon2.TestnestedflatbufferAsNumpy(),
|
lambda: mon2.TestnestedflatbufferAsNumpy(),
|
||||||
NumpyRequiredForThisFeature)
|
NumpyRequiredForThisFeature)
|
||||||
|
|
||||||
|
def test_nested_monster_testnestedflatbuffer(self):
|
||||||
|
b = flatbuffers.Builder(0)
|
||||||
|
|
||||||
|
# build another monster to nest inside testnestedflatbuffer
|
||||||
|
nestedB = flatbuffers.Builder(0)
|
||||||
|
nameStr = nestedB.CreateString("Nested Monster")
|
||||||
|
MyGame.Example.Monster.MonsterStart(nestedB)
|
||||||
|
MyGame.Example.Monster.MonsterAddHp(nestedB, 30)
|
||||||
|
MyGame.Example.Monster.MonsterAddName(nestedB, nameStr)
|
||||||
|
nestedMon = MyGame.Example.Monster.MonsterEnd(nestedB)
|
||||||
|
nestedB.Finish(nestedMon)
|
||||||
|
|
||||||
|
# write the nested FB bytes
|
||||||
|
sub_buf = MyGame.Example.Monster.MonsterMakeTestnestedflatbufferVectorFromBytes(
|
||||||
|
b, nestedB.Output())
|
||||||
|
|
||||||
|
# make the parent monster and include the bytes of the nested monster
|
||||||
|
MyGame.Example.Monster.MonsterStart(b)
|
||||||
|
MyGame.Example.Monster.MonsterAddTestnestedflatbuffer(b, sub_buf)
|
||||||
|
mon = MyGame.Example.Monster.MonsterEnd(b)
|
||||||
|
b.Finish(mon)
|
||||||
|
|
||||||
|
# inspect the resulting data:
|
||||||
|
mon2 = MyGame.Example.Monster.Monster.GetRootAsMonster(b.Bytes,
|
||||||
|
b.Head())
|
||||||
|
nestedMon2 = mon2.TestnestedflatbufferNestedRoot()
|
||||||
|
self.assertEqual(b"Nested Monster", nestedMon2.Name())
|
||||||
|
self.assertEqual(30, nestedMon2.Hp())
|
||||||
|
|
||||||
def test_nondefault_monster_testempty(self):
|
def test_nondefault_monster_testempty(self):
|
||||||
b = flatbuffers.Builder(0)
|
b = flatbuffers.Builder(0)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user