'Modify the object at dn using the attribute list.
:param dn: an LDAP DN
:param modlist: a list of tuples in the following form:
([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)'

def modify_s(self, dn, modlist):

    if server_fail:
        raise ldap.SERVER_DOWN
    key = self.key(dn)
    LOG.debug('modify    item:    dn=%(dn)s    attrs=%(attrs)s', {'dn': common.utf8_decode(dn), 'attrs': modlist})
    try:
        entry = self.db[key]
    except KeyError:
        LOG.debug('modify    item    failed:    dn=%s    not    found.', common.utf8_decode(dn))
        raise ldap.NO_SUCH_OBJECT
    for (cmd, k, v) in modlist:
        values = entry.setdefault(k, [])
        if (cmd == ldap.MOD_ADD):
            v = _internal_attr(k, v)
            for x in v:
                if (x in values):
                    raise ldap.TYPE_OR_VALUE_EXISTS
            values += v
        elif (cmd == ldap.MOD_REPLACE):
            values[:] = _internal_attr(k, v)
        elif (cmd == ldap.MOD_DELETE):
            if (v is None):
                if (not values):
                    LOG.debug('modify    item    failed:    item    has    no    attribute    "%s"    to    delete', k)
                    raise ldap.NO_SUCH_ATTRIBUTE
                values[:] = []
            else:
                for val in _internal_attr(k, v):
                    try:
                        values.remove(val)
                    except ValueError:
                        LOG.debug('modify    item    failed:    item    has    no    attribute    "%(k)s"    with    value    "%(v)s"    to    delete', {'k': k, 'v': val})
                        raise ldap.NO_SUCH_ATTRIBUTE
        else:
            LOG.debug('modify    item    failed:    unknown    command    %s', cmd)
            raise NotImplementedError(('modify_s    action    %s    not    implemented' % cmd))
    self.db[key] = entry
    self.db.sync()
