aaf2/utils.py
def write_u16le(f, value):
    f.write(pack(b"<H", value))
aaf2/utils.py
def encode_utf16le(data):
    return data.encode("utf-16le") + b"\x00\x00"
aaf2/utils.py
def read_u16le(f):
    (result, ) = unpack(b"<H", f.read(2))
    return result
aaf2/utils.py
def encode_u16le(value):
    return pack(b"<H", value)
aaf2/utils.py
def encode_auid_array(values):
    result = b""
    for item in values:
        if not isinstance(item, auid.AUID):
            item = auid.AUID(item)
        result += item.bytes_le
    return result
aaf2/utils.py
def mangle_name(name, pid, size):
    p = "%x" % pid
    max_size = size - len(p) - 1 -1
    new_name = squeeze_name(name, max_size)
    return "%s-%s" % (new_name, p)
aaf2/utils.py
def read_u8(f):
    (result, ) = unpack(b"B", f.read(1))
    return result
aaf2/utils.py
def read_u32le(f):
    (result, ) = unpack(b"<I", f.read(4))
    return result
aaf2/auid.py
class AUID(object):
    """
    A higher performance UUID class that is more specialised for AAF.
    """
    __slots__ = ('bytes_le')
    def __init__(self, hex=None, bytes_le=None, bytes_be=None, int=None):
        if bytes_le:
            self.bytes_le = bytearray(bytes_le)
        elif isinstance(hex, (uuid.UUID, AUID)):
            self.bytes_le = bytearray(hex.bytes_le)
        elif hex is not None:
            hex = hex.replace('urn:', '').replace('uuid:', '')
            hex = hex.strip('{}').replace('-', '')
            if len(hex) != 32:
                raise ValueError('badly formed hexadecimal UUID string')
            b = bytearray.fromhex(hex)
            self.bytes_le = bytearray(b[4-1::-1] + b[6-1:4-1:-1] + b[8-1:6-1:-1] + b[8:])
        elif bytes_be is not None:
            self.bytes_be = bytes_be
        elif int is not None:
            if int is 0:
                self.bytes_le = bytearray(16)
            else:
                self.bytes_le = bytearray(uuid.UUID(int=int).bytes_le)
        else:
            raise TypeError('one of the hex, bytes_le, bytes_be '
                            'or int arguments must be given')

    @property
    def bytes_be(self):
        return bytearray(self.bytes_le[4-1::-1]    + self.bytes_le[6-1:4-1:-1] +
                         self.bytes_le[8-1:6-1:-1] + self.bytes_le[8:])

    @bytes_be.setter
    def bytes_be(self, value):
        self.bytes_le = bytearray(value[4-1::-1]    + value[6-1:4-1:-1] +
                                  value[8-1:6-1:-1] + value[8:])

    @property
    def int(self):
        # done in big endian to match uuid.py
        num  = self.bytes_le[15]
        num += self.bytes_le[14] << 8
        num += self.bytes_le[13] << 16
        num += self.bytes_le[12] << 24
        num += self.bytes_le[11] << 32
        num += self.bytes_le[10] << 40
        num += self.bytes_le[ 9] << 48
        num += self.bytes_le[ 8] << 56

        # num += self.data3 << 64
        num += self.bytes_le[ 6] << 64
        num += self.bytes_le[ 7] << 72

        # num += self.data2 << 80
        num += self.bytes_le[ 4] << 80
        num += self.bytes_le[ 5] << 88

        # num += self.data1 << 96
        num += self.bytes_le[ 0] << 96
        num += self.bytes_le[ 1] << 104
        num += self.bytes_le[ 2] << 112
        num += self.bytes_le[ 3] << 120

        return num

    @property
    def hex(self):
        return '%032x' % self.int

    @property
    def uuid(self):
        return uuid.UUID(bytes_le=bytes(self.bytes_le))

    @property
    def data1(self):
        value  = self.bytes_le[0]
        value += self.bytes_le[1] << 8
        value += self.bytes_le[2] << 16
        value += self.bytes_le[3] << 24
        return value

    @property
    def data2(self):
        value  = self.bytes_le[4]
        value += self.bytes_le[5] << 8
        return value

    @property
    def data3(self):
        value  = self.bytes_le[6]
        value += self.bytes_le[7] << 8
        return value

    @property
    def data4(self):
        return self.bytes_le[8:]

    def __hash__(self):
        return hash(bytes(self.bytes_le))

    def __eq__(self, other):
        if isinstance(other, (AUID, uuid.UUID)):
            return self.bytes_le == other.bytes_le
        return NotImplemented

    def __repr__(self):
        hex = '%032x' % self.int
        return '%s-%s-%s-%s-%s' % (
            hex[:8], hex[8:12], hex[12:16], hex[16:20], hex[20:])
aaf2/utils.py
def encode_u32le(value):
    return pack(b"<I", value)
aaf2/utils.py
def encode_u8(value):
    return pack(b"B", value)
aaf2/utils.py
def encode_s64le(value):
    return pack(b"<q", value)
aaf2/utils.py
def decode_utf16le(data):
    return data.decode('utf-16le').split(u'\x00')[0]
aaf2/exceptions.py
class AAFPropertyError(AAFError):
    pass
aaf2/mobid.py
class MobID(object):
    __slots__ = ('bytes_le')
    def __init__(self, mobid=None, bytes_le=None, int=None):

        if bytes_le:
            self.bytes_le = bytearray(bytes_le)
        else:
            self.bytes_le = bytearray(32)

            if mobid is not None:
                self.urn = mobid

            if int is not None:
                self.int = int

    @staticmethod
    def new():
        """
        Static method for generating unique MobIDs. Uses uuid.uuid4() for generation.
        """
        return UniqueMobID()

    @property
    def material(self):
        """
        MobID material representation as a UUID
        """
        return auid.AUID(bytes_le=self.bytes_le[16:])

    @material.setter
    def material(self, value):
        self.bytes_le[16:] = value.bytes_le

    @property
    def SMPTELabel(self):
        return self.bytes_le[0:12]

    @SMPTELabel.setter
    def SMPTELabel(self, value):
        struct.pack_into(str('12B'), self.bytes_le, 0, *value)

    @property
    def length(self):
        return self.bytes_le[12]

    @length.setter
    def length(self, value):
        self.bytes_le[12] = value

    @property
    def instanceHigh(self):
        return self.bytes_le[13]

    @instanceHigh.setter
    def instanceHigh(self, value):
        self.bytes_le[13] = value

    @property
    def instanceMid(self):
        return self.bytes_le[14]

    @instanceMid.setter
    def instanceMid(self, value):
        self.bytes_le[14] = value

    @property
    def instanceLow(self):
        return self.bytes_le[15]

    @instanceLow.setter
    def instanceLow(self, value):
        self.bytes_le[15] = value

    @property
    def Data1(self):
        return unpack_u32le_from(self.bytes_le, 16)

    @Data1.setter
    def Data1(self, value):
        struct.pack_into(str('<I'), self.bytes_le, 16, value)

    @property
    def Data2(self):
        return unpack_u16le_from(self.bytes_le, 20)

    @Data2.setter
    def Data2(self, value):
        struct.pack_into(str('<H'), self.bytes_le, 20, value)

    @property
    def Data3(self):
        return unpack_u16le_from(self.bytes_le, 22)

    @Data3.setter
    def Data3(self, value):
        struct.pack_into(str('<H'), self.bytes_le, 22, value)

    @property
    def Data4(self):
        return self.bytes_le[24:32]

    @Data4.setter
    def Data4(self, value):
        struct.pack_into(str('8B'), self.bytes_le, 24, *value)

    def from_dict(self, d):
        """
        Set MobID from a dict
        """
        self.length = d.get("length", 0)
        self.instanceHigh = d.get("instanceHigh", 0)
        self.instanceMid = d.get("instanceMid", 0)
        self.instanceLow = d.get("instanceLow", 0)

        material = d.get("material", {'Data1':0, 'Data2':0, 'Data3':0, 'Data4': [0 for i in range(8)]})

        self.Data1 = material.get('Data1', 0)
        self.Data2 = material.get('Data2', 0)
        self.Data3 = material.get('Data3', 0)

        self.Data4 = material.get("Data4", [0 for i in range(8)])
        self.SMPTELabel = d.get("SMPTELabel", [0 for i in range(12)])

    def to_dict(self):
        """
        MobID representation as dict
        """

        material = {'Data1': self.Data1,
                    'Data2': self.Data2,
                    'Data3': self.Data3,
                    'Data4': list(self.Data4)
                    }

        return {'material':material,
                'length': self.length,
                'instanceHigh': self.instanceHigh,
                'instanceMid': self.instanceMid,
                'instanceLow': self.instanceLow,
                'SMPTELabel': list(self.SMPTELabel)
                }
    @property
    def int(self):
        """
        MobID representation as a int
        """
        return int_from_bytes(self.bytes_le, byte_order='big')

    @int.setter
    def int(self, value):
        # NOTE: interpreted as big endian
        self.bytes_le = bytearray(bytes_from_int(value, 32, byte_order='big'))

    def __int__(self):
        return self.int

    def __eq__(self, other):
        if isinstance(other, MobID):
            return self.bytes_le == other.bytes_le
        return NotImplemented

    def __lt__(self, other):
        if isinstance(other, MobID):
            return self.int < other.int
        return NotImplemented

    def __le__(self, other):
        if isinstance(other, MobID):
            return self.int <= other.int
        return NotImplemented

    def __gt__(self, other):
        if isinstance(other, MobID):
            return self.int > other.int
        return NotImplemented

    def __ge__(self, other):
        if isinstance(other, MobID):
            return self.int >= other.int
        return NotImplemented

    def __hash__(self):
        return hash(bytes(self.bytes_le))

    @property
    def urn(self):
        """
        MobID Uniform Resource Name representation.
        https://en.wikipedia.org/wiki/Uniform_Resource_Name
        """

        SMPTELabel = self.SMPTELabel
        Data4 = self.Data4

        # handle case UMIDs where the material number is half swapped
        if (SMPTELabel[11] == 0x00 and
            Data4[0] == 0x06 and Data4[1] == 0x0E and
            Data4[2] == 0x2B and Data4[3] == 0x34 and
            Data4[4] == 0x7F and Data4[5] == 0x7F):

            # print("case 1")
            f = "urn:smpte:umid:%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x." + \
             "%02x"  + \
             "%02x%02x%02x." + \
             "%02x%02x%02x%02x.%02x%02x%02x%02x.%08x.%04x%04x"

            return f % (
                 SMPTELabel[0], SMPTELabel[1], SMPTELabel[2],  SMPTELabel[3],
                 SMPTELabel[4], SMPTELabel[5], SMPTELabel[6],  SMPTELabel[7],
                 SMPTELabel[8], SMPTELabel[9], SMPTELabel[10], SMPTELabel[11],
                 self.length,
                 self.instanceHigh, self.instanceMid, self.instanceLow,
                 Data4[0], Data4[1], Data4[2], Data4[3],
                 Data4[4], Data4[5], Data4[6], Data4[7],
                 self.Data1, self.Data2, self.Data3)
        else:
            # print("case 2")
            f = "urn:smpte:umid:%02x%02x%02x%02x.%02x%02x%02x%02x.%02x%02x%02x%02x." + \
             "%02x"  + \
             "%02x%02x%02x." + \
             "%08x.%04x%04x.%02x%02x%02x%02x.%02x%02x%02x%02x"

            return f % (
                 SMPTELabel[0], SMPTELabel[1], SMPTELabel[2],  SMPTELabel[3],
                 SMPTELabel[4], SMPTELabel[5], SMPTELabel[6],  SMPTELabel[7],
                 SMPTELabel[8], SMPTELabel[9], SMPTELabel[10], SMPTELabel[11],
                 self.length,
                 self.instanceHigh, self.instanceMid, self.instanceLow,
                 self.Data1, self.Data2, self.Data3,
                 Data4[0], Data4[1], Data4[2], Data4[3],
                 Data4[4], Data4[5], Data4[6], Data4[7])

    @urn.setter
    def urn(self, value):
        s = str(value).lower()
        for item in ("urn:smpte:umid:", ".", '-', '0x'):
            s = s.replace(item, '')
        assert len(s) == 64

        SMPTELabel = [0 for i in range(12)]
        start = 0
        for i in range(12):
            end = start + 2
            v = s[start:end]
            SMPTELabel[i] = int(v, 16)
            start = end
        self.SMPTELabel = SMPTELabel
        self.length = int(s[24:26], 16)
        self.instanceHigh = int(s[26:28], 16)
        self.instanceMid = int(s[28:30], 16)
        self.instanceLow = int(s[30:32], 16)

        start = 32
        data = [0 for i in range(6)]
        for i in range(6):
            end = start + 2
            v = s[start:end]
            data[i] = int(v, 16)
            start = end
        # print(s[32:start])
        if (SMPTELabel[11] == 0x00 and
                   data[0] == 0x06 and data[1] == 0x0E and
                   data[2] == 0x2B and data[3] == 0x34 and
                   data[4] == 0x7F and data[5] == 0x7F):

            start = 32
            data4 = [0 for i in range(8)]
            for i in range(8):
                end = start + 2
                v = s[start:end]
                data4[i] = int(v, 16)
                start = end

            self.Data4 = data4
            self.Data1 = int(s[48:56], 16)
            self.Data2 = int(s[56:60], 16)
            self.Data3 = int(s[60:64], 16)

        else:
            self.Data1 = int(s[32:40], 16)
            self.Data2 = int(s[40:44], 16)
            self.Data3 = int(s[44:48], 16)

            start = 48
            data4 = [0 for i in range(8)]
            for i in range(8):
                end = start + 2
                v = s[start:end]
                data4[i] = int(v, 16)
                start = end
            self.Data4 = data4

    def __repr__(self):
        return str(self.urn)
aaf2/utils.py
def write_u8(f, value):
    f.write(pack(b"B", value))
aaf2/utils.py
def write_u32le(f, value):
    return f.write(pack(b"<I", value))
aaf2/exceptions.py
class AAFAttachError(AAFError):
    pass
aaf2/utils.py
def encode_utf16_array(data):
    result = b""
    for item in data:
        result += encode_utf16le(item)
    return result


Question: from io import BytesIO
from .utils import (
    read_u8,
    read_u16le,
    read_u32le,
    write_u8,
    write_u16le,
    write_u32le,
    decode_utf16le,
    encode_utf16le,
    encode_utf16_array,
    encode_auid_array,
    encode_u16le,
    encode_u32le,
    encode_u8,
    encode_s64le,
    mangle_name,
    )
from .auid import AUID
from .mobid import MobID
from .exceptions import AAFPropertyError, AAFAttachError
import weakref
import struct
        ref_classdef = self.ref_classdef

        for obj in value:
            assert ref_classdef.isinstance(obj.classdef)
            if obj.dir:
                raise AAFAttachError("object already attached")

        for obj in value:
            i = len(self.references)
            self.references.append(self.next_free_key)
            self.objects[i] = obj
            self.next_free_key += 1

        self.add_pid_entry()
        self.attach()

    def append(self, value):
        self.extend([value])

    @property
    def value(self):
        return [item for item in self]

    @value.setter
    @writeonly
    def value(self, value):
        if value is None:
            self.remove_pid_entry()
            return

        self.clear()
        self.extend(value)

    def detach(self):
        objects = {}
        for i, obj in enumerate(self):
            objects[i] = obj
        self.objects = objects

    def attach(self):

        if not self.parent.dir:
            return

        for i, obj in enumerate(self):
            ref = self.index_ref_name(i)

            dir_entry = self.parent.dir.get(ref)
            if dir_entry is None:
                dir_entry = self.parent.dir.makedir(ref)
            if obj.dir != dir_entry:
                obj.attach(dir_entry)


    def __repr__(self):
        return "<%s %s to %s %d items>" % (self.name, self.__class__.__name__, str(self.index_name), len(self.references))


class StrongRefSetProperty(Property):
    __slots__ = ('references', 'index_name', 'next_free_key', 'last_free_key', 'key_pid', 'key_size', 'objects')
    def __init__(self, parent, pid, format, version=PROPERTY_VERSION):
        super(StrongRefSetProperty, self).__init__(parent, pid, format, version)

        self.references = {}

        self.index_name = None

        self.next_free_key = 0
        self.last_free_key = 0xFFFFFFFF

        # Pid of the referenced objects unique_key
        self.key_pid = None
        self.key_size = None

        if self.attached:
            self.objects = weakref.WeakValueDictionary()
        else:
            self.objects = {}

    def copy(self, parent):
        p = super(StrongRefSetProperty, self).copy(parent)

        p.references = dict(self.references)
        p.next_free_key = self.next_free_key
        p.last_free_key = self.last_free_key
        p.key_size = self.key_size
        p.index_name = self.index_name
        p.key_pid = self.key_pid

        for key, value in self.items():
            ref = self.index_ref_name(key)
            dir_entry = None
            if parent.dir:
                dir_entry = parent.dir.get(ref)
                if dir_entry is None:
                    dir_entry = parent.dir.makedir(ref)
            p.objects[key] = value.copy(dir_entry)

        return p

    def encode(self, data):
        return encode_utf16le(data)

    def decode(self):
        self.index_name = decode_utf16le(self.data)

    def read_index(self):
        index_name = self.index_name + " index"
        index_dir = self.parent.dir.get(index_name)
        if not index_dir:
            raise AAFPropertyError("cannot find index stream: %s" % index_name)

        s = index_dir.open('r')
        # read the whole of the index
        f = BytesIO(s.read())

        count = read_u32le(f)
        self.next_free_key = read_u32le(f)
        self.last_free_key = read_u32le(f)
        self.key_pid = read_u16le(f)

Answer:         self.key_size = read_u8(f)