summaryrefslogtreecommitdiff
path: root/python
diff options
context:
space:
mode:
authorrw <me@rwinslow.com>2015-11-11 19:43:53 -0800
committerrw <me@rwinslow.com>2015-11-11 19:43:53 -0800
commit3232727ace325e8cb2732cf208e6d902a1160454 (patch)
tree8f23cd19ffa34b189bc2bc645e552e96dcce9ce8 /python
parent9dc5d378b147a6c70799810f8db0754dd89ea12e (diff)
downloadflatbuffers-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.py56
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)