forked from BigfootDev/flatbuffers
* feat: Added support for fixed sized arrays to python Problem: We encountered that using fixed arrays from C++ to python that python would not read those arrays correctly due to no size information being encoded in the byte array itself. Fix: Encode the sizes within the generated python file during code generation. Specfically we add GetArrayAsNumpy to the python version of table, which takes as input the length of the vector. When generating the python message files we include this length from the VectorType().fixed_length. * fix: added digit support for camel case to snake case conversion Problem: When including a number in the message name we would encounter cases where SnakeCase would not add the appropirate breaks. e.g. Int32Stamped -> int_32stamped rather than int_32_stamped. Fix: To fix this we can add the condition that we check if the current character is not lower and not a digit, that we check if the previous character was a lower or digit. If it was a lower or digit then we add the break. * fix: Array support for structures Problem: The python generated code for handling non-struct and struct vectors and arrays was inconsistent. The calls to populate the obj api was creating incorrect code. Solution: To fix this the VectorOfStruct and VectorOfNonStruct was rewritten to handle array cases and bring the two methods in line which each other. Testing: PythonTesting.sh now correctly runs and generates the code for array_test.fbs. Minor modifications were done on the test to use the new index accessor for struct arrays and the script correctly sources the location of the python code. * chore: clang format changes * Added code generated by scripts/generate_code. Modified GetArrayOfNonStruct slightly to allow for function overloading allowing the user to get a single element of an array or the whole array. * Added new_line parameter to OffsetPrefix to allow optional new lines to be added. This allows us to use the GenIndents method that automatically adds new lines instead. * Reupload of generated code from the scripts/generate_code.py * Removed new line in GetVectorAsNumpy. * Updated Array lengths to use Length methods where possible. Added fallthrough for GenTypePointer. Added digit check to CamelToSnake method. Added and modified tests for ToSnakeCase and CamelToSnake. * Added range check on the getter methods for vector and array types. Renamed == as is for python
139 lines
5.0 KiB
Python
139 lines
5.0 KiB
Python
# Copyright 2014 Google Inc. All rights reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
|
|
from . import encode
|
|
from . import number_types as N
|
|
|
|
|
|
class Table(object):
|
|
"""Table wraps a byte slice and provides read access to its data.
|
|
|
|
The variable `Pos` indicates the root of the FlatBuffers object therein."""
|
|
|
|
__slots__ = ("Bytes", "Pos")
|
|
|
|
def __init__(self, buf, pos):
|
|
N.enforce_number(pos, N.UOffsetTFlags)
|
|
|
|
self.Bytes = buf
|
|
self.Pos = pos
|
|
|
|
def Offset(self, vtableOffset):
|
|
"""Offset provides access into the Table's vtable.
|
|
|
|
Deprecated fields are ignored by checking the vtable's length."""
|
|
|
|
vtable = self.Pos - self.Get(N.SOffsetTFlags, self.Pos)
|
|
vtableEnd = self.Get(N.VOffsetTFlags, vtable)
|
|
if vtableOffset < vtableEnd:
|
|
return self.Get(N.VOffsetTFlags, vtable + vtableOffset)
|
|
return 0
|
|
|
|
def Indirect(self, off):
|
|
"""Indirect retrieves the relative offset stored at `offset`."""
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
return off + encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
|
|
|
def String(self, off):
|
|
"""String gets a string from data stored inside the flatbuffer."""
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
|
start = off + N.UOffsetTFlags.bytewidth
|
|
length = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
|
return bytes(self.Bytes[start:start+length])
|
|
|
|
def VectorLen(self, off):
|
|
"""VectorLen retrieves the length of the vector whose offset is stored
|
|
at "off" in this object."""
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
|
|
off += self.Pos
|
|
off += encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
|
ret = encode.Get(N.UOffsetTFlags.packer_type, self.Bytes, off)
|
|
return ret
|
|
|
|
def Vector(self, off):
|
|
"""Vector retrieves the start of data of the vector whose offset is
|
|
stored at "off" in this object."""
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
|
|
off += self.Pos
|
|
x = off + self.Get(N.UOffsetTFlags, off)
|
|
# data starts after metadata containing the vector length
|
|
x += N.UOffsetTFlags.bytewidth
|
|
return x
|
|
|
|
def Union(self, t2, off):
|
|
"""Union initializes any Table-derived type to point to the union at
|
|
the given offset."""
|
|
assert type(t2) is Table
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
|
|
off += self.Pos
|
|
t2.Pos = off + self.Get(N.UOffsetTFlags, off)
|
|
t2.Bytes = self.Bytes
|
|
|
|
def Get(self, flags, off):
|
|
"""
|
|
Get retrieves a value of the type specified by `flags` at the
|
|
given offset.
|
|
"""
|
|
N.enforce_number(off, N.UOffsetTFlags)
|
|
return flags.py_type(encode.Get(flags.packer_type, self.Bytes, off))
|
|
|
|
def GetSlot(self, slot, d, validator_flags):
|
|
N.enforce_number(slot, N.VOffsetTFlags)
|
|
if validator_flags is not None:
|
|
N.enforce_number(d, validator_flags)
|
|
off = self.Offset(slot)
|
|
if off == 0:
|
|
return d
|
|
return self.Get(validator_flags, self.Pos + off)
|
|
|
|
def GetVectorAsNumpy(self, flags, off):
|
|
"""
|
|
GetVectorAsNumpy returns the vector that starts at `Vector(off)`
|
|
as a numpy array with the type specified by `flags`. The array is
|
|
a `view` into Bytes, so modifying the returned array will
|
|
modify Bytes in place.
|
|
"""
|
|
offset = self.Vector(off)
|
|
length = self.VectorLen(off) # TODO: length accounts for bytewidth, right?
|
|
numpy_dtype = N.to_numpy_type(flags)
|
|
return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, offset)
|
|
|
|
def GetArrayAsNumpy(self, flags, off, length):
|
|
"""
|
|
GetArrayAsNumpy returns the array with fixed width that starts at `Vector(offset)`
|
|
with length `length` as a numpy array with the type specified by `flags`. The
|
|
array is a `view` into Bytes so modifying the returned will modify Bytes in place.
|
|
"""
|
|
numpy_dtype = N.to_numpy_type(flags)
|
|
return encode.GetVectorAsNumpy(numpy_dtype, self.Bytes, length, off)
|
|
|
|
def GetVOffsetTSlot(self, slot, d):
|
|
"""
|
|
GetVOffsetTSlot retrieves the VOffsetT that the given vtable location
|
|
points to. If the vtable value is zero, the default value `d`
|
|
will be returned.
|
|
"""
|
|
|
|
N.enforce_number(slot, N.VOffsetTFlags)
|
|
N.enforce_number(d, N.VOffsetTFlags)
|
|
|
|
off = self.Offset(slot)
|
|
if off == 0:
|
|
return d
|
|
return off
|