diff options
author | rw <me@rwinslow.com> | 2015-11-11 19:43:53 -0800 |
---|---|---|
committer | rw <me@rwinslow.com> | 2015-11-11 19:43:53 -0800 |
commit | 3232727ace325e8cb2732cf208e6d902a1160454 (patch) | |
tree | 8f23cd19ffa34b189bc2bc645e552e96dcce9ce8 /python | |
parent | 9dc5d378b147a6c70799810f8db0754dd89ea12e (diff) | |
download | flatbuffers-3232727ace325e8cb2732cf208e6d902a1160454.tar.gz flatbuffers-3232727ace325e8cb2732cf208e6d902a1160454.tar.bz2 flatbuffers-3232727ace325e8cb2732cf208e6d902a1160454.zip |
Python: Improve Builder user interface.
+ Add state to the Builder object to track if we are inside a table,
and if we are finished building the buffer.
+ Use this data to check that a buffer is being built correctly.
+ Raise an exception if a buffer is not being built correctly.
+ Test that the exceptions happen as expected.
Based on d236dea.
Diffstat (limited to 'python')
-rw-r--r-- | python/flatbuffers/builder.py | 56 |
1 files changed, 37 insertions, 19 deletions
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py index ed509704..6e346591 100644 --- a/python/flatbuffers/builder.py +++ b/python/flatbuffers/builder.py @@ -32,7 +32,7 @@ class OffsetArithmeticError(RuntimeError): pass -class NotInObjectError(RuntimeError): +class IsNotNestedError(RuntimeError): """ Error caused by using a Builder to write Object data when not inside an Object. @@ -40,7 +40,7 @@ class NotInObjectError(RuntimeError): pass -class ObjectIsNestedError(RuntimeError): +class IsNestedError(RuntimeError): """ Error caused by using a Builder to begin an Object when an Object is already being built. @@ -63,6 +63,12 @@ class BuilderSizeError(RuntimeError): """ pass +class BuilderNotFinishedError(RuntimeError): + """ + Error caused by not calling `Finish` before calling `Output`. + """ + pass + # VtableMetadataFields is the count of metadata fields in each vtable. VtableMetadataFields = 2 @@ -85,7 +91,7 @@ class Builder(object): """ __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd", - "vtables") + "vtables", "nested", "finished") """ Maximum buffer size constant, in bytes. @@ -110,13 +116,19 @@ class Builder(object): self.minalign = 1 self.objectEnd = None self.vtables = [] + self.nested = False + self.finished = False def Output(self): """ Output returns the portion of the buffer that has been used for - writing data. + writing data. It raises BuilderNotFinishedError if the buffer has not + been finished with `Finish`. """ + if not self.finished: + raise BuilderNotFinishedError() + return self.Bytes[self.Head():] def StartObject(self, numfields): @@ -128,6 +140,7 @@ class Builder(object): self.current_vtable = [0 for _ in range_func(numfields)] self.objectEnd = self.Offset() self.minalign = 1 + self.nested = True def WriteVtable(self): """ @@ -236,10 +249,8 @@ class Builder(object): def EndObject(self): """EndObject writes data necessary to finish object construction.""" - if self.current_vtable is None: - msg = ("flatbuffers: Tried to write the end of an Object when " - "the Builder was not currently writing an Object.") - raise NotInObjectError(msg) + self.assertNested() + self.nested = False return self.WriteVtable() def growByteBuffer(self): @@ -336,6 +347,7 @@ class Builder(object): """ self.assertNotNested() + self.nested = True self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems) self.Prep(alignment, elemSize*numElems) # In case alignment > int. return self.Offset() @@ -343,6 +355,8 @@ class Builder(object): def EndVector(self, vectorNumElems): """EndVector writes data necessary to finish vector construction.""" + self.assertNested() + self.nested = False # we already made space for this, so write without PrependUint32 self.PlaceUOffsetT(vectorNumElems) return self.Offset() @@ -351,6 +365,7 @@ class Builder(object): """CreateString writes a null-terminated byte string as a vector.""" self.assertNotNested() + self.nested = True if isinstance(s, compat.string_types): x = s.encode() @@ -369,18 +384,24 @@ class Builder(object): return self.EndVector(len(x)) + def assertNested(self): + """ + Check that we are in the process of building an object. + """ + + if not self.nested: + raise IsNotNestedError() + def assertNotNested(self): """ Check that no other objects are being built while making this object. If not, raise an exception. """ - if self.current_vtable is not None: - msg = ("flatbuffers: Tried to write a new Object when the " - "Builder was already writing an Object.") - raise ObjectIsNestedError(msg) + if self.nested: + raise IsNestedError() - def assertNested(self, obj): + def assertStructIsInline(self, obj): """ Structs are always stored inline, so need to be created right where they are used. You'll get this error if you created it @@ -399,11 +420,7 @@ class Builder(object): buffer. """ - if self.current_vtable is None: - msg = ("flatbuffers: Tried to write an Object field when " - "the Builder was not currently writing an Object.") - raise NotInObjectError(msg) - + self.assertNested() self.current_vtable[slotnum] = self.Offset() def Finish(self, rootTable): @@ -411,6 +428,7 @@ class Builder(object): N.enforce_number(rootTable, N.UOffsetTFlags) self.Prep(self.minalign, N.UOffsetTFlags.bytewidth) self.PrependUOffsetTRelative(rootTable) + self.finished = True return self.Head() def Prepend(self, flags, off): @@ -470,7 +488,7 @@ class Builder(object): N.enforce_number(d, N.UOffsetTFlags) if x != d: - self.assertNested(x) + self.assertStructIsInline(x) self.Slot(v) def PrependBool(self, x): self.Prepend(N.BoolFlags, x) |