def record_field_change(self, field, old_value, new_value,
                            name_field=None):
        def serialize_changed_obj(item, name_field):
            return (getattr(item, name_field),
                    item.get_absolute_url(),
                    item.id)

        def serialize_changed_obj_list(items, name_field):
            if name_field:
                return [
                    serialize_changed_obj(item, name_field)
                    for item in items
                ]
            else:
                return [
                    (item,)
                    for item in items
                ]

        if (type(old_value) != type(new_value) and
            not (isinstance(old_value, six.string_types) and
                 isinstance(new_value, six.string_types)) and
            old_value is not None and new_value is not None):
            raise ValueError("%s (%s) and %s (%s) are of two different value "
                             "types." % (old_value, type(old_value),
                                         new_value, type(new_value)))

        if hasattr(old_value, "__iter__"):
            old_set = set(old_value)
            new_set = set(new_value)

            self.fields_changed[field] = {
                'old': serialize_changed_obj_list(old_value, name_field),
                'new': serialize_changed_obj_list(new_value, name_field),
                'added': serialize_changed_obj_list(new_set - old_set,
                                                    name_field),
                'removed': serialize_changed_obj_list(old_set - new_set,
                                                      name_field)
            }
        elif field == 'submitter':
            self.fields_changed[field] = {
                'old': [serialize_changed_obj(old_value, name_field)],
                'new': [serialize_changed_obj(new_value, name_field)],
            }
        else:
            self.fields_changed[field] = {
                'old': (old_value,),
                'new': (new_value,),
            }
Handle legacy authentication timeout.
dataset/ETHPy150Open reviewboard/reviewboard/reviewboard/changedescs/models.py/ChangeDescription.record_field_change--crossover with--dataset/ETHPy150Open kuri65536/python-for-android/python3-alpha/python-libs/pyxmpp2/ext/legacyauth.py/LegacyClientStream.auth_timeout