google / google/flatbuffers

Pack() method incorrectly accesses fixed array of structs as single object in Python object API

Open
#9,061 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
26.5k
Forks
3.7k
PR merge metrics
No merged PRs in 30d

Description

When a struct contains a fixed-size array of structs, the generated Pack() method in the Python object API treats self.items as a single struct instance instead of a list, causing runtime errors.

This is inconsistent with _UnPack(), the .pyi stub, and CreateOuter(), all of which correctly treat the field as a list.

flatc version: 25.12.19

Schema to reproduce:
```fbsnamespace bug;

struct Inner {
x: float;
y: float;
}

struct Outer {
items: [Inner: 3];
}

table Root {
data: Outer (native_inline);
}

root_type Root;
```

The following command
`flatc --python --gen-object-api --python-typing --gen-onefile --filename-suffix "" bug.fbs`

results in an incorrectly generated `Pack`:
```
pythondef Pack(self, builder):
return CreateOuter(builder, self.items.x, self.items.y) # self.items is a list
```

and a correct `_UnPack`:
```
pythondef _UnPack(self, outer):
self.items = []
for i in range(outer.ItemsLength()):
inner_ = InnerT.InitFromObj(outer.Items(i))
self.items.append(inner_)
Generated CreateOuter() — expects lists
pythondef CreateOuter(builder, items_x, items_y):
builder.Prep(4, 24)
for _idx0 in range(3, 0, -1):
builder.Prep(4, 8)
builder.PrependFloat32(items_y[_idx0-1]) # indexes into list
builder.PrependFloat32(items_x[_idx0-1]) # indexes into list
return builder.Offset()
```

The generated stubs expect list (as expected):
```
pythonclass OuterT(object):
items: typing.List[InnerT] # list, not a single InnerT
```

I would expect Pack() to iterate over self.items and extract scalar fields into lists, consistent with how CreateOuter() consumes them:

```
def Pack(self, builder):
return CreateOuter(
builder,
[_item.x for _item in self.items],
[_item.y for _item in self.items],
)
```

Notes

The bug also affects nested cases where the element struct itself contains fixed arrays, requiring 2D list comprehensions
As a workaround we are patching the generated Pack() method as a post-processing step in our build pipeline, which fixes the issue locally, similar to below:
```
def Pack(self, builder):
return CreateOuter(
builder,
[_item.x for _item in self.items],
[_item.y for _item in self.items],
)
```

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.