@bacpypes_debugging
def SequenceOf(klass):
    if _debug: SequenceOf._debug("SequenceOf %r", klass)

    global _sequence_of_map
    global _sequence_of_classes, _array_of_classes

    # if this has already been built, return the cached one
    if klass in _sequence_of_map:
        if _debug: SequenceOf._debug("    - found in cache")
        return _sequence_of_map[klass]

    # no SequenceOf(SequenceOf(...)) allowed
    if klass in _sequence_of_classes:
        raise TypeError("nested sequences disallowed")
    # no SequenceOf(ArrayOf(...)) allowed
    if klass in _array_of_classes:
        raise TypeError("sequences of arrays disallowed")

    # define a generic class for lists
    @bacpypes_debugging
    class _SequenceOf:

        subtype = None

        def __init__(self, value=None):
            if _debug: _SequenceOf._debug("(%r)__init__ %r (subtype=%r)", self.__class__.__name__, value, self.subtype)

            if value is None:
                self.value = []
            elif isinstance(value, list):
                self.value = value
            else:
                raise TypeError("invalid constructor datatype")

        def append(self, value):
            if issubclass(self.subtype, Atomic):
                pass
            elif issubclass(self.subtype, AnyAtomic) and not isinstance(value, Atomic):
                raise TypeError("instance of an atomic type required")
            elif not isinstance(value, self.subtype):
                raise TypeError("%s value required" % (self.subtype.__name__,))
            self.value.append(value)

        def __len__(self):
            return len(self.value)

        def __getitem__(self, item):
            return self.value[item]

        def encode(self, taglist):
            if _debug: _SequenceOf._debug("(%r)encode %r", self.__class__.__name__, taglist)
            for value in self.value:
                if issubclass(self.subtype, (Atomic, AnyAtomic)):
                    # a helper cooperates between the atomic value and the tag
                    helper = self.subtype(value)

                    # build a tag and encode the data into it
                    tag = Tag()
                    helper.encode(tag)

                    # now encode the tag
                    taglist.append(tag)
                elif isinstance(value, self.subtype):
                    # it must have its own encoder
                    value.encode(taglist)
                else:
                    raise TypeError("%s must be a %s" % (value, self.subtype.__name__))

        def decode(self, taglist):
            if _debug: _SequenceOf._debug("(%r)decode %r", self.__class__.__name__, taglist)

            while len(taglist) != 0:
                tag = taglist.Peek()
                if tag.tagClass == Tag.closingTagClass:
                    return

                if issubclass(self.subtype, (Atomic, AnyAtomic)):
                    if _debug: _SequenceOf._debug("    - building helper: %r %r", self.subtype, tag)
                    taglist.Pop()

                    # a helper cooperates between the atomic value and the tag
                    helper = self.subtype(tag)

                    # save the value
                    self.value.append(helper.value)
                else:
                    if _debug: _SequenceOf._debug("    - building value: %r", self.subtype)
                    # build an element
                    value = self.subtype()

                    # let it decode itself
                    value.decode(taglist)

                    # save what was built
                    self.value.append(value)

        def debug_contents(self, indent=1, file=sys.stdout, _ids=None):
            i = 0
            for value in self.value:
                if issubclass(self.subtype, (Atomic, AnyAtomic)):
                    file.write("%s[%d] = %r\n" % ("    " * indent, i, value))
                elif isinstance(value, self.subtype):
                    file.write("%s[%d]" % ("    " * indent, i))
                    value.debug_contents(indent+1, file, _ids)
                else:
                    file.write("%s[%d] %s must be a %s" % ("    " * indent, i, value, self.subtype.__name__))
                i += 1

        def dict_contents(self, use_dict=None, as_class=dict):
            # return sequences as arrays
            mapped_value = []

            for value in self.value:
                if issubclass(self.subtype, Atomic):
                    mapped_value.append(value)              ### ambiguous
                elif issubclass(self.subtype, AnyAtomic):
                    mapped_value.append(value.value)        ### ambiguous
                elif isinstance(value, self.subtype):
                    mapped_value.append(value.dict_contents(as_class=as_class))

            # return what we built
            return mapped_value

    # constrain it to a list of a specific type of item
    setattr(_SequenceOf, 'subtype', klass)
    _SequenceOf.__name__ = 'SequenceOf' + klass.__name__
    if _debug: SequenceOf._debug("    - build this class: %r", _SequenceOf)

    # cache this type
    _sequence_of_map[klass] = _SequenceOf
    _sequence_of_classes[_SequenceOf] = 1

    # return this new type
    return _SequenceOf

#
#   Array
#
#   Arrays of things are a derived class of Array to make it easier to check
#   to see if a property is an array of something.
#
Applies get_db_prep_save of item_field on value items.
dataset/ETHPy150Open JoelBender/bacpypes/py27/bacpypes/constructeddata.py/SequenceOf--crossover with--dataset/ETHPy150Open django-nonrel/djangotoolbox/djangotoolbox/fields.py/AbstractIterableField.get_db_prep_save