Squashed 'third_party/flatbuffers/' content from commit acc9990ab

Change-Id: I48550d40d78fea996ebe74e9723a5d1f910de491
git-subtree-dir: third_party/flatbuffers
git-subtree-split: acc9990abd2206491480291b0f85f925110102ea
diff --git a/python/.gitignore b/python/.gitignore
new file mode 100644
index 0000000..a771946
--- /dev/null
+++ b/python/.gitignore
@@ -0,0 +1,2 @@
+/dist/
+/*.egg-info/
diff --git a/python/__init__.py b/python/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/python/__init__.py
diff --git a/python/flatbuffers/__init__.py b/python/flatbuffers/__init__.py
new file mode 100644
index 0000000..d14872a
--- /dev/null
+++ b/python/flatbuffers/__init__.py
@@ -0,0 +1,17 @@
+# 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 .builder import Builder
+from .table import Table
+from .compat import range_func as compat_range
diff --git a/python/flatbuffers/builder.py b/python/flatbuffers/builder.py
new file mode 100644
index 0000000..d04ee85
--- /dev/null
+++ b/python/flatbuffers/builder.py
@@ -0,0 +1,755 @@
+# 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 number_types as N
+from .number_types import (UOffsetTFlags, SOffsetTFlags, VOffsetTFlags)
+
+from . import encode
+from . import packer
+
+from . import compat
+from .compat import range_func
+from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+## @file
+## @addtogroup flatbuffers_python_api
+## @{
+
+## @cond FLATBUFFERS_INTERNAL
+class OffsetArithmeticError(RuntimeError):
+    """
+    Error caused by an Offset arithmetic error. Probably caused by bad
+    writing of fields. This is considered an unreachable situation in
+    normal circumstances.
+    """
+    pass
+
+
+class IsNotNestedError(RuntimeError):
+    """
+    Error caused by using a Builder to write Object data when not inside
+    an Object.
+    """
+    pass
+
+
+class IsNestedError(RuntimeError):
+    """
+    Error caused by using a Builder to begin an Object when an Object is
+    already being built.
+    """
+    pass
+
+
+class StructIsNotInlineError(RuntimeError):
+    """
+    Error caused by using a Builder to write a Struct at a location that
+    is not the current Offset.
+    """
+    pass
+
+
+class BuilderSizeError(RuntimeError):
+    """
+    Error caused by causing a Builder to exceed the hardcoded limit of 2
+    gigabytes.
+    """
+    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
+## @endcond
+
+class Builder(object):
+    """ A Builder is used to construct one or more FlatBuffers.
+
+    Typically, Builder objects will be used from code generated by the `flatc`
+    compiler.
+
+    A Builder constructs byte buffers in a last-first manner for simplicity and
+    performance during reading.
+
+    Internally, a Builder is a state machine for creating FlatBuffer objects.
+
+    It holds the following internal state:
+        - Bytes: an array of bytes.
+        - current_vtable: a list of integers.
+        - vtables: a hash of vtable entries.
+
+    Attributes:
+      Bytes: The internal `bytearray` for the Builder.
+      finished: A boolean determining if the Builder has been finalized.
+    """
+
+    ## @cond FLATBUFFERS_INTENRAL
+    __slots__ = ("Bytes", "current_vtable", "head", "minalign", "objectEnd",
+                 "vtables", "nested", "finished")
+
+    """Maximum buffer size constant, in bytes.
+
+    Builder will never allow it's buffer grow over this size.
+    Currently equals 2Gb.
+    """
+    MAX_BUFFER_SIZE = 2**31
+    ## @endcond
+
+    def __init__(self, initialSize):
+        """Initializes a Builder of size `initial_size`.
+
+        The internal buffer is grown as needed.
+        """
+
+        if not (0 <= initialSize <= Builder.MAX_BUFFER_SIZE):
+            msg = "flatbuffers: Cannot create Builder larger than 2 gigabytes."
+            raise BuilderSizeError(msg)
+
+        self.Bytes = bytearray(initialSize)
+        ## @cond FLATBUFFERS_INTERNAL
+        self.current_vtable = None
+        self.head = UOffsetTFlags.py_type(initialSize)
+        self.minalign = 1
+        self.objectEnd = None
+        self.vtables = {}
+        self.nested = False
+        ## @endcond
+        self.finished = False
+
+
+    def Output(self):
+        """Return the portion of the buffer that has been used for writing data.
+
+        This is the typical way to access the FlatBuffer data inside the
+        builder. If you try to access `Builder.Bytes` directly, you would need
+        to manually index it with `Head()`, since the buffer is constructed
+        backwards.
+
+        It raises BuilderNotFinishedError if the buffer has not been finished
+        with `Finish`.
+        """
+
+        if not self.finished:
+            raise BuilderNotFinishedError()
+
+        return self.Bytes[self.Head():]
+
+    ## @cond FLATBUFFERS_INTERNAL
+    def StartObject(self, numfields):
+        """StartObject initializes bookkeeping for writing a new object."""
+
+        self.assertNotNested()
+
+        # use 32-bit offsets so that arithmetic doesn't overflow.
+        self.current_vtable = [0 for _ in range_func(numfields)]
+        self.objectEnd = self.Offset()
+        self.nested = True
+
+    def WriteVtable(self):
+        """
+        WriteVtable serializes the vtable for the current object, if needed.
+
+        Before writing out the vtable, this checks pre-existing vtables for
+        equality to this one. If an equal vtable is found, point the object to
+        the existing vtable and return.
+
+        Because vtable values are sensitive to alignment of object data, not
+        all logically-equal vtables will be deduplicated.
+
+        A vtable has the following format:
+          <VOffsetT: size of the vtable in bytes, including this value>
+          <VOffsetT: size of the object in bytes, including the vtable offset>
+          <VOffsetT: offset for a field> * N, where N is the number of fields
+                     in the schema for this type. Includes deprecated fields.
+        Thus, a vtable is made of 2 + N elements, each VOffsetT bytes wide.
+
+        An object has the following format:
+          <SOffsetT: offset to this object's vtable (may be negative)>
+          <byte: data>+
+        """
+
+        # Prepend a zero scalar to the object. Later in this function we'll
+        # write an offset here that points to the object's vtable:
+        self.PrependSOffsetTRelative(0)
+
+        objectOffset = self.Offset()
+
+        vtKey = []
+        trim = True
+        for elem in reversed(self.current_vtable):
+            if elem == 0:
+                if trim:
+                    continue
+            else:
+                elem = objectOffset - elem
+                trim = False
+
+            vtKey.append(elem)
+
+        vtKey = tuple(vtKey)
+        vt2Offset = self.vtables.get(vtKey)
+        if vt2Offset is None:
+            # Did not find a vtable, so write this one to the buffer.
+
+            # Write out the current vtable in reverse , because
+            # serialization occurs in last-first order:
+            i = len(self.current_vtable) - 1
+            trailing = 0
+            trim = True
+            while i >= 0:
+                off = 0
+                elem = self.current_vtable[i]
+                i -= 1
+
+                if elem == 0:
+                    if trim:
+                        trailing += 1
+                        continue
+                else:
+                    # Forward reference to field;
+                    # use 32bit number to ensure no overflow:
+                    off = objectOffset - elem
+                    trim = False
+
+                self.PrependVOffsetT(off)
+
+            # The two metadata fields are written last.
+
+            # First, store the object bytesize:
+            objectSize = UOffsetTFlags.py_type(objectOffset - self.objectEnd)
+            self.PrependVOffsetT(VOffsetTFlags.py_type(objectSize))
+
+            # Second, store the vtable bytesize:
+            vBytes = len(self.current_vtable) - trailing + VtableMetadataFields
+            vBytes *= N.VOffsetTFlags.bytewidth
+            self.PrependVOffsetT(VOffsetTFlags.py_type(vBytes))
+
+            # Next, write the offset to the new vtable in the
+            # already-allocated SOffsetT at the beginning of this object:
+            objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
+            encode.Write(packer.soffset, self.Bytes, objectStart,
+                         SOffsetTFlags.py_type(self.Offset() - objectOffset))
+
+            # Finally, store this vtable in memory for future
+            # deduplication:
+            self.vtables[vtKey] = self.Offset()
+        else:
+            # Found a duplicate vtable.
+            objectStart = SOffsetTFlags.py_type(len(self.Bytes) - objectOffset)
+            self.head = UOffsetTFlags.py_type(objectStart)
+
+            # Write the offset to the found vtable in the
+            # already-allocated SOffsetT at the beginning of this object:
+            encode.Write(packer.soffset, self.Bytes, self.Head(),
+                         SOffsetTFlags.py_type(vt2Offset - objectOffset))
+
+        self.current_vtable = None
+        return objectOffset
+
+    def EndObject(self):
+        """EndObject writes data necessary to finish object construction."""
+        self.assertNested()
+        self.nested = False
+        return self.WriteVtable()
+
+    def growByteBuffer(self):
+        """Doubles the size of the byteslice, and copies the old data towards
+           the end of the new buffer (since we build the buffer backwards)."""
+        if len(self.Bytes) == Builder.MAX_BUFFER_SIZE:
+            msg = "flatbuffers: cannot grow buffer beyond 2 gigabytes"
+            raise BuilderSizeError(msg)
+
+        newSize = min(len(self.Bytes) * 2, Builder.MAX_BUFFER_SIZE)
+        if newSize == 0:
+            newSize = 1
+        bytes2 = bytearray(newSize)
+        bytes2[newSize-len(self.Bytes):] = self.Bytes
+        self.Bytes = bytes2
+    ## @endcond
+
+    def Head(self):
+        """Get the start of useful data in the underlying byte buffer.
+
+        Note: unlike other functions, this value is interpreted as from the
+        left.
+        """
+        ## @cond FLATBUFFERS_INTERNAL
+        return self.head
+        ## @endcond
+
+    ## @cond FLATBUFFERS_INTERNAL
+    def Offset(self):
+        """Offset relative to the end of the buffer."""
+        return UOffsetTFlags.py_type(len(self.Bytes) - self.Head())
+
+    def Pad(self, n):
+        """Pad places zeros at the current offset."""
+        for i in range_func(n):
+            self.Place(0, N.Uint8Flags)
+
+    def Prep(self, size, additionalBytes):
+        """
+        Prep prepares to write an element of `size` after `additional_bytes`
+        have been written, e.g. if you write a string, you need to align
+        such the int length field is aligned to SizeInt32, and the string
+        data follows it directly.
+        If all you need to do is align, `additionalBytes` will be 0.
+        """
+
+        # Track the biggest thing we've ever aligned to.
+        if size > self.minalign:
+            self.minalign = size
+
+        # Find the amount of alignment needed such that `size` is properly
+        # aligned after `additionalBytes`:
+        alignSize = (~(len(self.Bytes) - self.Head() + additionalBytes)) + 1
+        alignSize &= (size - 1)
+
+        # Reallocate the buffer if needed:
+        while self.Head() < alignSize+size+additionalBytes:
+            oldBufSize = len(self.Bytes)
+            self.growByteBuffer()
+            updated_head = self.head + len(self.Bytes) - oldBufSize
+            self.head = UOffsetTFlags.py_type(updated_head)
+        self.Pad(alignSize)
+
+    def PrependSOffsetTRelative(self, off):
+        """
+        PrependSOffsetTRelative prepends an SOffsetT, relative to where it
+        will be written.
+        """
+
+        # Ensure alignment is already done:
+        self.Prep(N.SOffsetTFlags.bytewidth, 0)
+        if not (off <= self.Offset()):
+            msg = "flatbuffers: Offset arithmetic error."
+            raise OffsetArithmeticError(msg)
+        off2 = self.Offset() - off + N.SOffsetTFlags.bytewidth
+        self.PlaceSOffsetT(off2)
+    ## @endcond
+
+    def PrependUOffsetTRelative(self, off):
+        """Prepends an unsigned offset into vector data, relative to where it
+        will be written.
+        """
+
+        # Ensure alignment is already done:
+        self.Prep(N.UOffsetTFlags.bytewidth, 0)
+        if not (off <= self.Offset()):
+            msg = "flatbuffers: Offset arithmetic error."
+            raise OffsetArithmeticError(msg)
+        off2 = self.Offset() - off + N.UOffsetTFlags.bytewidth
+        self.PlaceUOffsetT(off2)
+
+    ## @cond FLATBUFFERS_INTERNAL
+    def StartVector(self, elemSize, numElems, alignment):
+        """
+        StartVector initializes bookkeeping for writing a new vector.
+
+        A vector has the following format:
+          - <UOffsetT: number of elements in this vector>
+          - <T: data>+, where T is the type of elements of this vector.
+        """
+
+        self.assertNotNested()
+        self.nested = True
+        self.Prep(N.Uint32Flags.bytewidth, elemSize*numElems)
+        self.Prep(alignment, elemSize*numElems)  # In case alignment > int.
+        return self.Offset()
+    ## @endcond
+
+    def EndVector(self, vectorNumElems):
+        """EndVector writes data necessary to finish vector construction."""
+
+        self.assertNested()
+        ## @cond FLATBUFFERS_INTERNAL
+        self.nested = False
+        ## @endcond
+        # we already made space for this, so write without PrependUint32
+        self.PlaceUOffsetT(vectorNumElems)
+        return self.Offset()
+
+    def CreateString(self, s, encoding='utf-8', errors='strict'):
+        """CreateString writes a null-terminated byte string as a vector."""
+
+        self.assertNotNested()
+        ## @cond FLATBUFFERS_INTERNAL
+        self.nested = True
+        ## @endcond
+
+        if isinstance(s, compat.string_types):
+            x = s.encode(encoding, errors)
+        elif isinstance(s, compat.binary_types):
+            x = s
+        else:
+            raise TypeError("non-string passed to CreateString")
+
+        self.Prep(N.UOffsetTFlags.bytewidth, (len(x)+1)*N.Uint8Flags.bytewidth)
+        self.Place(0, N.Uint8Flags)
+
+        l = UOffsetTFlags.py_type(len(s))
+        ## @cond FLATBUFFERS_INTERNAL
+        self.head = UOffsetTFlags.py_type(self.Head() - l)
+        ## @endcond
+        self.Bytes[self.Head():self.Head()+l] = x
+
+        return self.EndVector(len(x))
+
+    def CreateByteVector(self, x):
+        """CreateString writes a byte vector."""
+
+        self.assertNotNested()
+        ## @cond FLATBUFFERS_INTERNAL
+        self.nested = True
+        ## @endcond
+
+        if not isinstance(x, compat.binary_types):
+            raise TypeError("non-byte vector passed to CreateByteVector")
+
+        self.Prep(N.UOffsetTFlags.bytewidth, len(x)*N.Uint8Flags.bytewidth)
+
+        l = UOffsetTFlags.py_type(len(x))
+        ## @cond FLATBUFFERS_INTERNAL
+        self.head = UOffsetTFlags.py_type(self.Head() - l)
+        ## @endcond
+        self.Bytes[self.Head():self.Head()+l] = x
+
+        return self.EndVector(len(x))
+
+    def CreateNumpyVector(self, x):
+        """CreateNumpyVector writes a numpy array into the buffer."""
+
+        if np is None:
+            # Numpy is required for this feature
+            raise NumpyRequiredForThisFeature("Numpy was not found.")
+
+        if not isinstance(x, np.ndarray):
+            raise TypeError("non-numpy-ndarray passed to CreateNumpyVector")
+
+        if x.dtype.kind not in ['b', 'i', 'u', 'f']:
+            raise TypeError("numpy-ndarray holds elements of unsupported datatype")
+
+        if x.ndim > 1:
+            raise TypeError("multidimensional-ndarray passed to CreateNumpyVector")
+
+        self.StartVector(x.itemsize, x.size, x.dtype.alignment)
+
+        # Ensure little endian byte ordering
+        if x.dtype.str[0] == "<":
+            x_lend = x
+        else:
+            x_lend = x.byteswap(inplace=False)
+
+        # Calculate total length
+        l = UOffsetTFlags.py_type(x_lend.itemsize * x_lend.size)
+        ## @cond FLATBUFFERS_INTERNAL
+        self.head = UOffsetTFlags.py_type(self.Head() - l)
+        ## @endcond
+
+        # tobytes ensures c_contiguous ordering
+        self.Bytes[self.Head():self.Head()+l] = x_lend.tobytes(order='C')
+        
+        return self.EndVector(x.size)
+
+    ## @cond FLATBUFFERS_INTERNAL
+    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.nested:
+            raise IsNestedError()
+
+    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
+        elsewhere.
+        """
+
+        N.enforce_number(obj, N.UOffsetTFlags)
+        if obj != self.Offset():
+            msg = ("flatbuffers: Tried to write a Struct at an Offset that "
+                   "is different from the current Offset of the Builder.")
+            raise StructIsNotInlineError(msg)
+
+    def Slot(self, slotnum):
+        """
+        Slot sets the vtable key `voffset` to the current location in the
+        buffer.
+
+        """
+        self.assertNested()
+        self.current_vtable[slotnum] = self.Offset()
+    ## @endcond
+
+    def __Finish(self, rootTable, sizePrefix, file_identifier=None):
+        """Finish finalizes a buffer, pointing to the given `rootTable`."""
+        N.enforce_number(rootTable, N.UOffsetTFlags)
+
+        if file_identifier is not None:
+            self.Prep(N.UOffsetTFlags.bytewidth, N.Uint8Flags.bytewidth*4)
+            
+            # Convert bytes object file_identifier to an array of 4 8-bit integers,
+            # and use big-endian to enforce size compliance.
+            # https://docs.python.org/2/library/struct.html#format-characters
+            file_identifier = N.struct.unpack(">BBBB", file_identifier)
+            for i in range(encode.FILE_IDENTIFIER_LENGTH-1, -1, -1):
+                # Place the bytes of the file_identifer in reverse order:
+                self.Place(file_identifier[i], N.Uint8Flags)   
+                
+        self.PrependUOffsetTRelative(rootTable)
+        if sizePrefix:
+            size = len(self.Bytes) - self.Head()
+            N.enforce_number(size, N.Int32Flags)
+            self.PrependInt32(size)
+        self.finished = True
+        return self.Head()
+
+    def Finish(self, rootTable, file_identifier=None):
+        """Finish finalizes a buffer, pointing to the given `rootTable`."""
+        return self.__Finish(rootTable, False, file_identifier=file_identifier)
+
+    def FinishSizePrefixed(self, rootTable, file_identifier=None):
+        """
+        Finish finalizes a buffer, pointing to the given `rootTable`,
+        with the size prefixed.
+        """
+        return self.__Finish(rootTable, True, file_identifier=file_identifier)
+
+    ## @cond FLATBUFFERS_INTERNAL
+    def Prepend(self, flags, off):
+        self.Prep(flags.bytewidth, 0)
+        self.Place(off, flags)
+
+    def PrependSlot(self, flags, o, x, d):
+        N.enforce_number(x, flags)
+        N.enforce_number(d, flags)
+        if x != d:
+            self.Prepend(flags, x)
+            self.Slot(o)
+
+    def PrependBoolSlot(self, *args): self.PrependSlot(N.BoolFlags, *args)
+
+    def PrependByteSlot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
+
+    def PrependUint8Slot(self, *args): self.PrependSlot(N.Uint8Flags, *args)
+
+    def PrependUint16Slot(self, *args): self.PrependSlot(N.Uint16Flags, *args)
+
+    def PrependUint32Slot(self, *args): self.PrependSlot(N.Uint32Flags, *args)
+
+    def PrependUint64Slot(self, *args): self.PrependSlot(N.Uint64Flags, *args)
+
+    def PrependInt8Slot(self, *args): self.PrependSlot(N.Int8Flags, *args)
+
+    def PrependInt16Slot(self, *args): self.PrependSlot(N.Int16Flags, *args)
+
+    def PrependInt32Slot(self, *args): self.PrependSlot(N.Int32Flags, *args)
+
+    def PrependInt64Slot(self, *args): self.PrependSlot(N.Int64Flags, *args)
+
+    def PrependFloat32Slot(self, *args): self.PrependSlot(N.Float32Flags,
+                                                          *args)
+
+    def PrependFloat64Slot(self, *args): self.PrependSlot(N.Float64Flags,
+                                                          *args)
+
+    def PrependUOffsetTRelativeSlot(self, o, x, d):
+        """
+        PrependUOffsetTRelativeSlot prepends an UOffsetT onto the object at
+        vtable slot `o`. If value `x` equals default `d`, then the slot will
+        be set to zero and no other data will be written.
+        """
+
+        if x != d:
+            self.PrependUOffsetTRelative(x)
+            self.Slot(o)
+
+    def PrependStructSlot(self, v, x, d):
+        """
+        PrependStructSlot prepends a struct onto the object at vtable slot `o`.
+        Structs are stored inline, so nothing additional is being added.
+        In generated code, `d` is always 0.
+        """
+
+        N.enforce_number(d, N.UOffsetTFlags)
+        if x != d:
+            self.assertStructIsInline(x)
+            self.Slot(v)
+
+    ## @endcond
+
+    def PrependBool(self, x):
+        """Prepend a `bool` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.BoolFlags, x)
+
+    def PrependByte(self, x):
+        """Prepend a `byte` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Uint8Flags, x)
+
+    def PrependUint8(self, x):
+        """Prepend an `uint8` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Uint8Flags, x)
+
+    def PrependUint16(self, x):
+        """Prepend an `uint16` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Uint16Flags, x)
+
+    def PrependUint32(self, x):
+        """Prepend an `uint32` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Uint32Flags, x)
+
+    def PrependUint64(self, x):
+        """Prepend an `uint64` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Uint64Flags, x)
+
+    def PrependInt8(self, x):
+        """Prepend an `int8` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Int8Flags, x)
+
+    def PrependInt16(self, x):
+        """Prepend an `int16` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Int16Flags, x)
+
+    def PrependInt32(self, x):
+        """Prepend an `int32` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Int32Flags, x)
+
+    def PrependInt64(self, x):
+        """Prepend an `int64` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Int64Flags, x)
+
+    def PrependFloat32(self, x):
+        """Prepend a `float32` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Float32Flags, x)
+
+    def PrependFloat64(self, x):
+        """Prepend a `float64` to the Builder buffer.
+
+        Note: aligns and checks for space.
+        """
+        self.Prepend(N.Float64Flags, x)
+
+##############################################################
+
+    ## @cond FLATBUFFERS_INTERNAL
+    def PrependVOffsetT(self, x): self.Prepend(N.VOffsetTFlags, x)
+
+    def Place(self, x, flags):
+        """
+        Place prepends a value specified by `flags` to the Builder,
+        without checking for available space.
+        """
+
+        N.enforce_number(x, flags)
+        self.head = self.head - flags.bytewidth
+        encode.Write(flags.packer_type, self.Bytes, self.Head(), x)
+
+    def PlaceVOffsetT(self, x):
+        """PlaceVOffsetT prepends a VOffsetT to the Builder, without checking
+        for space.
+        """
+        N.enforce_number(x, N.VOffsetTFlags)
+        self.head = self.head - N.VOffsetTFlags.bytewidth
+        encode.Write(packer.voffset, self.Bytes, self.Head(), x)
+
+    def PlaceSOffsetT(self, x):
+        """PlaceSOffsetT prepends a SOffsetT to the Builder, without checking
+        for space.
+        """
+        N.enforce_number(x, N.SOffsetTFlags)
+        self.head = self.head - N.SOffsetTFlags.bytewidth
+        encode.Write(packer.soffset, self.Bytes, self.Head(), x)
+
+    def PlaceUOffsetT(self, x):
+        """PlaceUOffsetT prepends a UOffsetT to the Builder, without checking
+        for space.
+        """
+        N.enforce_number(x, N.UOffsetTFlags)
+        self.head = self.head - N.UOffsetTFlags.bytewidth
+        encode.Write(packer.uoffset, self.Bytes, self.Head(), x)
+    ## @endcond
+
+## @cond FLATBUFFERS_INTERNAL
+def vtableEqual(a, objectStart, b):
+    """vtableEqual compares an unwritten vtable to a written vtable."""
+
+    N.enforce_number(objectStart, N.UOffsetTFlags)
+
+    if len(a) * N.VOffsetTFlags.bytewidth != len(b):
+        return False
+
+    for i, elem in enumerate(a):
+        x = encode.Get(packer.voffset, b, i * N.VOffsetTFlags.bytewidth)
+
+        # Skip vtable entries that indicate a default value.
+        if x == 0 and elem == 0:
+            pass
+        else:
+            y = objectStart - elem
+            if x != y:
+                return False
+    return True
+## @endcond
+## @}
diff --git a/python/flatbuffers/compat.py b/python/flatbuffers/compat.py
new file mode 100644
index 0000000..2fc9cca
--- /dev/null
+++ b/python/flatbuffers/compat.py
@@ -0,0 +1,81 @@
+# Copyright 2016 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.
+
+""" A tiny version of `six` to help with backwards compability. Also includes
+ compatibility helpers for numpy. """
+
+import sys
+import imp
+
+PY2 = sys.version_info[0] == 2
+PY26 = sys.version_info[0:2] == (2, 6)
+PY27 = sys.version_info[0:2] == (2, 7)
+PY275 = sys.version_info[0:3] >= (2, 7, 5)
+PY3 = sys.version_info[0] == 3
+PY34 = sys.version_info[0:2] >= (3, 4)
+
+if PY3:
+    string_types = (str,)
+    binary_types = (bytes,bytearray)
+    range_func = range
+    memoryview_type = memoryview
+    struct_bool_decl = "?"
+else:
+    string_types = (unicode,)
+    if PY26 or PY27:
+        binary_types = (str,bytearray)
+    else:
+        binary_types = (str,)
+    range_func = xrange
+    if PY26 or (PY27 and not PY275):
+        memoryview_type = buffer
+        struct_bool_decl = "<b"
+    else:
+        memoryview_type = memoryview
+        struct_bool_decl = "?"
+
+# Helper functions to facilitate making numpy optional instead of required
+
+def import_numpy():
+    """
+    Returns the numpy module if it exists on the system,
+    otherwise returns None.
+    """
+    try:
+        imp.find_module('numpy')
+        numpy_exists = True
+    except ImportError:
+        numpy_exists = False
+
+    if numpy_exists:
+        # We do this outside of try/except block in case numpy exists
+        # but is not installed correctly. We do not want to catch an
+        # incorrect installation which would manifest as an
+        # ImportError.
+        import numpy as np
+    else:
+        np = None
+
+    return np
+
+
+class NumpyRequiredForThisFeature(RuntimeError):
+    """
+    Error raised when user tries to use a feature that
+    requires numpy without having numpy installed.
+    """
+    pass
+
+
+# NOTE: Future Jython support may require code here (look at `six`).
diff --git a/python/flatbuffers/encode.py b/python/flatbuffers/encode.py
new file mode 100644
index 0000000..c4f1a59
--- /dev/null
+++ b/python/flatbuffers/encode.py
@@ -0,0 +1,42 @@
+# 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 number_types as N
+from . import packer
+from .compat import memoryview_type
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+
+FILE_IDENTIFIER_LENGTH=4
+
+def Get(packer_type, buf, head):
+    """ Get decodes a value at buf[head] using `packer_type`. """
+    return packer_type.unpack_from(memoryview_type(buf), head)[0]
+
+
+def GetVectorAsNumpy(numpy_type, buf, count, offset):
+    """ GetVecAsNumpy decodes values starting at buf[head] as
+    `numpy_type`, where `numpy_type` is a numpy dtype. """
+    if np is not None:
+        # TODO: could set .flags.writeable = False to make users jump through
+        #       hoops before modifying...
+        return np.frombuffer(buf, dtype=numpy_type, count=count, offset=offset)
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
+
+
+def Write(packer_type, buf, head, n):
+    """ Write encodes `n` at buf[head] using `packer_type`. """
+    packer_type.pack_into(buf, head, n)
diff --git a/python/flatbuffers/number_types.py b/python/flatbuffers/number_types.py
new file mode 100644
index 0000000..47942ff
--- /dev/null
+++ b/python/flatbuffers/number_types.py
@@ -0,0 +1,181 @@
+# 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.
+
+import collections
+import struct
+
+from . import packer
+from .compat import import_numpy, NumpyRequiredForThisFeature
+
+np = import_numpy()
+
+# For reference, see:
+# https://docs.python.org/2/library/ctypes.html#ctypes-fundamental-data-types-2
+
+# These classes could be collections.namedtuple instances, but those are new
+# in 2.6 and we want to work towards 2.5 compatability.
+
+class BoolFlags(object):
+    bytewidth = 1
+    min_val = False
+    max_val = True
+    py_type = bool
+    name = "bool"
+    packer_type = packer.boolean
+
+
+class Uint8Flags(object):
+    bytewidth = 1
+    min_val = 0
+    max_val = (2**8) - 1
+    py_type = int
+    name = "uint8"
+    packer_type = packer.uint8
+
+
+class Uint16Flags(object):
+    bytewidth = 2
+    min_val = 0
+    max_val = (2**16) - 1
+    py_type = int
+    name = "uint16"
+    packer_type = packer.uint16
+
+
+class Uint32Flags(object):
+    bytewidth = 4
+    min_val = 0
+    max_val = (2**32) - 1
+    py_type = int
+    name = "uint32"
+    packer_type = packer.uint32
+
+
+class Uint64Flags(object):
+    bytewidth = 8
+    min_val = 0
+    max_val = (2**64) - 1
+    py_type = int
+    name = "uint64"
+    packer_type = packer.uint64
+
+
+class Int8Flags(object):
+    bytewidth = 1
+    min_val = -(2**7)
+    max_val = (2**7) - 1
+    py_type = int
+    name = "int8"
+    packer_type = packer.int8
+
+
+class Int16Flags(object):
+    bytewidth = 2
+    min_val = -(2**15)
+    max_val = (2**15) - 1
+    py_type = int
+    name = "int16"
+    packer_type = packer.int16
+
+
+class Int32Flags(object):
+    bytewidth = 4
+    min_val = -(2**31)
+    max_val = (2**31) - 1
+    py_type = int
+    name = "int32"
+    packer_type = packer.int32
+
+
+class Int64Flags(object):
+    bytewidth = 8
+    min_val = -(2**63)
+    max_val = (2**63) - 1
+    py_type = int
+    name = "int64"
+    packer_type = packer.int64
+
+
+class Float32Flags(object):
+    bytewidth = 4
+    min_val = None
+    max_val = None
+    py_type = float
+    name = "float32"
+    packer_type = packer.float32
+
+
+class Float64Flags(object):
+    bytewidth = 8
+    min_val = None
+    max_val = None
+    py_type = float
+    name = "float64"
+    packer_type = packer.float64
+
+
+class SOffsetTFlags(Int32Flags):
+    pass
+
+
+class UOffsetTFlags(Uint32Flags):
+    pass
+
+
+class VOffsetTFlags(Uint16Flags):
+    pass
+
+
+def valid_number(n, flags):
+    if flags.min_val is None and flags.max_val is None:
+        return True
+    return flags.min_val <= n <= flags.max_val
+
+
+def enforce_number(n, flags):
+    if flags.min_val is None and flags.max_val is None:
+        return
+    if not flags.min_val <= n <= flags.max_val:
+        raise TypeError("bad number %s for type %s" % (str(n), flags.name))
+
+
+def float32_to_uint32(n):
+    packed = struct.pack("<1f", n)
+    (converted,) = struct.unpack("<1L", packed)
+    return converted
+
+
+def uint32_to_float32(n):
+    packed = struct.pack("<1L", n)
+    (unpacked,) = struct.unpack("<1f", packed)
+    return unpacked
+
+
+def float64_to_uint64(n):
+    packed = struct.pack("<1d", n)
+    (converted,) = struct.unpack("<1Q", packed)
+    return converted
+
+
+def uint64_to_float64(n):
+    packed = struct.pack("<1Q", n)
+    (unpacked,) = struct.unpack("<1d", packed)
+    return unpacked
+
+
+def to_numpy_type(number_type):
+    if np is not None:
+        return np.dtype(number_type.name).newbyteorder('<')
+    else:
+        raise NumpyRequiredForThisFeature('Numpy was not found.')
diff --git a/python/flatbuffers/packer.py b/python/flatbuffers/packer.py
new file mode 100644
index 0000000..20ee9f1
--- /dev/null
+++ b/python/flatbuffers/packer.py
@@ -0,0 +1,42 @@
+# Copyright 2016 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.
+
+"""
+Provide pre-compiled struct packers for encoding and decoding.
+
+See: https://docs.python.org/2/library/struct.html#format-characters
+"""
+
+import struct
+from . import compat
+
+
+boolean = struct.Struct(compat.struct_bool_decl)
+
+uint8 = struct.Struct("<B")
+uint16 = struct.Struct("<H")
+uint32 = struct.Struct("<I")
+uint64 = struct.Struct("<Q")
+
+int8 = struct.Struct("<b")
+int16 = struct.Struct("<h")
+int32 = struct.Struct("<i")
+int64 = struct.Struct("<q")
+
+float32 = struct.Struct("<f")
+float64 = struct.Struct("<d")
+
+uoffset = uint32
+soffset = int32
+voffset = uint16
diff --git a/python/flatbuffers/table.py b/python/flatbuffers/table.py
new file mode 100644
index 0000000..adc76ca
--- /dev/null
+++ b/python/flatbuffers/table.py
@@ -0,0 +1,129 @@
+# 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 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
diff --git a/python/flatbuffers/util.py b/python/flatbuffers/util.py
new file mode 100644
index 0000000..a5a7838
--- /dev/null
+++ b/python/flatbuffers/util.py
@@ -0,0 +1,43 @@
+# Copyright 2017 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
+from . import packer
+
+def GetSizePrefix(buf, offset):
+	"""Extract the size prefix from a buffer."""
+	return encode.Get(packer.int32, buf, offset)
+
+def GetBufferIdentifier(buf, offset, size_prefixed=False):
+        """Extract the file_identifier from a buffer"""
+        if size_prefixed:
+            # increase offset by size of UOffsetTFlags
+            offset += number_types.UOffsetTFlags.bytewidth
+        # increase offset by size of root table pointer
+        offset += number_types.UOffsetTFlags.bytewidth
+        # end of FILE_IDENTIFIER
+        end = offset + encode.FILE_IDENTIFIER_LENGTH
+        return buf[offset:end]
+
+def BufferHasIdentifier(buf, offset, file_identifier, size_prefixed=False):
+        got = GetBufferIdentifier(buf, offset, size_prefixed=size_prefixed)
+        return got == file_identifier
+
+def RemoveSizePrefix(buf, offset):
+	"""
+	Create a slice of a size-prefixed buffer that has
+	its position advanced just past the size prefix.
+	"""
+	return buf, offset + number_types.Int32Flags.bytewidth
diff --git a/python/setup.cfg b/python/setup.cfg
new file mode 100644
index 0000000..3c6e79c
--- /dev/null
+++ b/python/setup.cfg
@@ -0,0 +1,2 @@
+[bdist_wheel]
+universal=1
diff --git a/python/setup.py b/python/setup.py
new file mode 100644
index 0000000..b3fc566
--- /dev/null
+++ b/python/setup.py
@@ -0,0 +1,71 @@
+# Copyright 2016 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.
+
+import os
+from datetime import datetime
+from setuptools import setup
+
+
+def version():
+    version = os.getenv('VERSION', None)
+    if version:
+        # Most git tags are prefixed with 'v' (example: v1.2.3) this is
+        # never desirable for artifact repositories, so we strip the
+        # leading 'v' if it's present.
+        return version[1:] if version.startswith('v') else version
+    else:
+        # Default version is an ISO8601 compiliant datetime. PyPI doesn't allow
+        # the colon ':' character in its versions, and time is required to allow
+        # for multiple publications to master in one day. This datetime string
+        # uses the "basic" ISO8601 format for both its date and time components
+        # to avoid issues with the colon character (ISO requires that date and
+        # time components of a date-time string must be uniformly basic or
+        # extended, which is why the date component does not have dashes.
+        #
+        # Publications using datetime versions should only be made from master
+        # to represent the HEAD moving forward.
+        version = datetime.utcnow().strftime('%Y%m%d%H%M%S')
+        print("VERSION environment variable not set, using datetime instead: {}"
+              .format(version))
+
+    return version
+
+setup(
+    name='flatbuffers',
+    version=version(),
+    license='Apache 2.0',
+    author='FlatBuffers Contributors',
+    author_email='me@rwinslow.com',
+    url='https://google.github.io/flatbuffers/',
+    long_description=('Python runtime library for use with the '
+                      '`Flatbuffers <https://google.github.io/flatbuffers/>`_ '
+                      'serialization format.'),
+    packages=['flatbuffers'],
+    include_package_data=True,
+    requires=[],
+    description='The FlatBuffers serialization format for Python',
+    classifiers=[
+        'Intended Audience :: Developers',
+        'License :: OSI Approved :: Apache Software License',
+        'Operating System :: OS Independent',
+        'Programming Language :: Python',
+        'Programming Language :: Python :: 2',
+        'Programming Language :: Python :: 3',
+        'Topic :: Software Development :: Libraries :: Python Modules',
+    ],
+    project_urls={
+        'Documentation': 'https://google.github.io/flatbuffers/',
+        'Source': 'https://github.com/google/flatbuffers',
+    },
+)
\ No newline at end of file