示例#1
0
def expireat_handler(client, argv):
    '''
    EXPIREAT has the same effect and semantic as EXPIRE, but instead of specifying the number of seconds
    representing the TTL (time to live), it takes an absolute Unix timestamp (seconds since January 1, 1970).

    Please for the specific semantics of the command refer to the documentation of EXPIRE.

    .. code::
        EXPIREAT key timestamp

    :return: 1 if the timeout was set. 0 if key does not exist or the timeout could not be set (see: EXPIRE).
    :rtype: int

    '''

    key, exptime = argv[1], argv[2]
    try:
        exptime = int(exptime)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key)
    except KeyError:
        return 0

    obj.expire_time = exptime
    return 1
示例#2
0
def append_handler(client, argv):
    '''
    If key already exists and is a string, this command appends the value at the end of the string.
    If key does not exist it is created and set as an empty string, so APPEND will be similar to SET
    in this special case.

    .. code::
        APPEND key value

    :return: the length of the string after the append operation.
    :rtype: int

    '''

    key, value = argv[1], argv[2]

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
    except KeyError:
        length = len(value)
        try:
            value = int(value)
        except ValueError:
            pass
        client.db.key_space[key] = RedisStringObject(value)
        return length
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    obj.value = obj.get_bytes() + value

    return len(obj.value)
示例#3
0
def lpushx_handler(client, argv):
    '''
    Inserts value at the head of the list stored at key, only if key already exists and holds a list.
    In contrary to LPUSH, no operation will be performed when key does not yet exist.

    .. code::
        LPUSHX key value

    :return: the length of the list after the push operation.
    :rtype: int

    '''

    key, value = argv[1], argv[2]

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    obj.push(value)
    return len(obj)
示例#4
0
def lrem_handler(client, argv):
    '''
    Removes the first count occurrences of elements equal to value from the list stored at key. The
    count argument influences the operation in the following ways:

    * count > 0: Remove elements equal to value moving from head to tail.
    * count < 0: Remove elements equal to value moving from tail to head.
    * count = 0: Remove all elements equal to value.

    For example, LREM list -2 "hello" will remove the last two occurrences of "hello" in the list
    stored at list.

    Note that non-existing keys are treated like empty lists, so when key does not exist, the command
    will always return 0.

    .. code::
        LREM key count value

    :return: the number of removed elements.
    :rtype: int

    '''

    key, count, value = argv[1], argv[2], argv[3]
    try:
        count = int(count)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    if count < 0:
        count *= -1
        objlst = obj[::-1]
        revd = True
    else:
        objlst = obj[:]
        revd = False

    if count == 0:
        count = len(obj)

    counter = 0
    while count:
        try:
            objlst.remove(value)
        except ValueError:
            break
        count -= 1
        counter += 1

    if revd:
        objlst.reverse()
    obj.value = objlst
    return counter
示例#5
0
def lpop_handler(client, argv):
    '''
    Removes and returns the first element of the list stored at key.

    .. code::
        LPOP key

    :return: the value of the first element, or nil when key does not exist.
    :rtype: str

    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    try:
        return obj.pop()
    except IndexError:
        return None
示例#6
0
def getbit_handler(client, argv):
    '''
    Returns the bit value at offset in the string value stored at key.

    When offset is beyond the string length, the string is assumed to be a contiguous space with 0 bits.
    When key does not exist it is assumed to be an empty string, so offset is always out of range and the
    value is also assumed to be a contiguous space with 0 bits.

    .. code::
        GETBIT key offset

    '''

    key, offset = argv[1], argv[2]

    try:
        offset = int(offset)
    except ValueError:
        abort(message='bit offset is not an integer or out of range')

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
        ba = bitarray.bitarray()
        ba.frombytes(obj.get_bytes())
        return int(ba[offset])
    except KeyError:
        return None
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')
    except IndexError:
        return 0
示例#7
0
def lpush_handler(client, argv):
    '''
    Insert all the specified values at the head of the list stored at key. If key does not exist,
    it is created as empty list before performing the push operations. When key holds a value that
    is not a list, an error is returned.

    It is possible to push multiple elements using a single command call just specifying multiple
    arguments at the end of the command. Elements are inserted one after the other to the head of
    the list, from the leftmost element to the rightmost element. So for instance the command LPUSH
    mylist a b c will result into a list containing c as first element, b as second element and a
    as third element.

    .. code::
        LPUSH key value [value ...]

    :return: the length of the list after the push operations.
    :rtype: int

    '''

    key, values = argv[1], argv[2:]

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        obj = RedisListObject()
        client.db.key_space[key] = obj
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    # for value in values:
    obj.push(*values)

    return len(obj)
示例#8
0
def lindex_handler(client, argv):
    '''
    Returns the element at index index in the list stored at key. The index is zero-based, so 0
    means the first element, 1 the second element and so on. Negative indices can be used to designate
    elements starting at the tail of the list. Here, -1 means the last element, -2 means the penultimate
    and so forth.

    When the value at key is not a list, an error is returned.

    .. code::
        LINDEX key index

    :return: the requested element, or nil when index is out of range.
    :rtype: str

    '''

    key, index = argv[1], argv[2]
    try:
        index = int(index)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return None
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        return obj[index]
    except IndexError:
        return None
示例#9
0
def getset_handler(client, argv):
    '''
    Atomically sets key to value and returns the old value stored at key. Returns an error when key
    exists but does not hold a string value.

    .. code::
        GETSET key value

    '''

    key, value = argv[1], argv[2]

    try:
        value = int(value)
    except ValueError:
        pass

    try:
        obj = get_object(client.db, key, type=RedisStringObject)

        orig_value = obj.get_bytes()
        obj.value = value
    except KeyError:
        orig_value = None
        client.db.key_space[key] = RedisStringObject(value)
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    return RedisStringObject(orig_value)
示例#10
0
def lset_handler(client, argv):
    '''

    Sets the list element at index to value. For more information on the index argument, see LINDEX.

    An error is returned for out of range indexes.

    .. code::
        LSET key index value

    '''

    key, index, value = argv[1], argv[2], argv[3]

    try:
        index = int(index)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        abort(message='index out of range')
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    if index < 0:
        index = len(obj) + index

    try:
        obj[index] = value
    except IndexError:
        abort(message='index out of range')
    return True
示例#11
0
def incrbyfloat_handler(client, argv):
    '''
    Increment the string representing a floating point number stored at key by the specified increment.
    If the key does not exist, it is set to 0 before performing the operation. An error is returned if
    one of the following conditions occur:

    * The key contains a value of the wrong type (not a string).
    * The current key content or the specified increment are not parsable as a double precision floating
      point number.

    If the command is successful the new incremented value is stored as the new value of the key (replacing
    the old one), and returned to the caller as a string.

    Both the value already contained in the string key and the increment argument can be optionally provided
    in exponential notation, however the value computed after the increment is stored consistently in the
    same format, that is, an integer number followed (if needed) by a dot, and a variable number of digits
    representing the decimal part of the number. Trailing zeroes are always removed.

    The precision of the output is fixed at 17 digits after the decimal point regardless of the actual internal
    precision of the computation.

    .. code::
        INCRBYFLOAT key increment

    :return: the value of key after the increment.
    :rtype: bytes

    '''

    key, increment = argv[1], argv[2]

    try:
        increment = Decimal(increment.decode())
    except InvalidOperation:
        abort(message='value is not a valid float')

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
        value = obj.get_integer()
    except KeyError:
        value = 0
        obj = RedisStringObject()
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        value = obj.get_decimal()
    except InvalidOperation:
        abort(message='value is not a valid float')

    value += increment

    obj.value = value
    client.db.key_space[key] = obj
    return obj
示例#12
0
def setnx_handler(client, argv):
    '''
    Set key to hold string value if key does not exist. In that case, it is equal to SET.
    When key already holds a value, no operation is performed. SETNX is short for "SET if N ot e X ists".

    .. code::
        SETNX key value

    :return: 1 if key was set, otherwise 0
    :rtype: int

    '''

    key, value = argv[1], argv[2]
    try:
        get_object(client.db, key)
        return 0
    except KeyError:
        client.db.key_space[key] = RedisStringObject(value)
    return 1
示例#13
0
def msetnx_handler(client, argv):
    '''
    Sets the given keys to their respective values. MSETNX will not perform any operation at all even
    if just a single key already exists.

    Because of this semantic MSETNX can be used in order to set different keys representing different
    fields of an unique logic object in a way that ensures that either all the fields or none at all
    are set.

    MSETNX is atomic, so all given keys are set at once. It is not possible for clients to see that some
    of the keys were updated while others are unchanged.

    .. code::
        MSETNX key value [key value ...]

    :return: 1 if the all the keys were set. 0 if no key was set (at least one key already existed).
    :rtype: int

    '''

    if len(argv) & 1 == 0:
        abort(message='wrong number of arguments for MSET')

    all_set = True
    for key, value in group_iter(argv[1:], n=2):
        try:
            get_object(client.db, key)
            all_set = False
            break
        except KeyError:
            pass

    if all_set:
        for key, value in group_iter(argv[1:], n=2):
            client.db.key_space[key] = RedisStringObject(value=value)

    return int(all_set)
示例#14
0
def ltrim_handler(client, argv):
    '''
    Trim an existing list so that it will contain only the specified range of elements specified.
    Both start and stop are zero-based indexes, where 0 is the first element of the list (the head),
    1 the next element and so on.

    For example: LTRIM foobar 0 2 will modify the list stored at foobar so that only the first three
    elements of the list will remain.

    start and end can also be negative numbers indicating offsets from the end of the list, where -1 is
    the last element of the list, -2 the penultimate element and so on.

    Out of range indexes will not produce an error: if start is larger than the end of the list, or
    start > end, the result will be an empty list (which causes key to be removed). If end is larger
    than the end of the list, Redis will treat it like the last element of the list.

    .. code::
        LTRIM key start stop

    '''

    key, start, stop = argv[1], argv[2], argv[3]

    try:
        start = int(start)
        stop = int(stop)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return True
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    if start < 0:
        start = len(obj) + start
    if stop < 0:
        stop = len(obj) + stop

    obj.value = obj[start:stop]
    return True
示例#15
0
def get_handler(client, argv):
    '''
    Get the value of key. If the key does not exist the special value nil is returned.
    An error is returned if the value stored at key is not a string, because GET only handles string values.

    .. code::
        GET key

    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key, RedisStringObject)
        return obj
    except KeyError:
        return None
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')
示例#16
0
def persist_handler(client, argv):
    '''
    Remove the existing timeout on key, turning the key from volatile (a key with an expire set) to
    persistent (a key that will never expire as no timeout is associated).

    .. code::
        PERSIST key

    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key)
    except KeyError:
        return 0

    obj.expire_time = None
    return 1
示例#17
0
def bitcount_handler(client, argv):
    '''
    Count the number of set bits (population counting) in a string.

    By default all the bytes contained in the string are examined. It is possible to specify the counting
    operation only in an interval passing the additional arguments start and end.

    Like for the GETRANGE command start and end can contain negative values in order to index bytes starting
    from the end of the string, where -1 is the last byte, -2 is the penultimate, and so forth.

    Non-existent keys are treated as empty strings, so the command will return zero.

    .. code::
        BITCOUNT key [start end]

    :return: The number of bits set to 1.
    :rtype: int

    '''

    key, start, end = argv[1], None, None
    if len(argv) == 3 or len(argv) > 4:
        abort(message='syntax error')
    try:
        if len(argv) == 4:
            start, end = int(argv[2]), int(argv[3])
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisStringObject)
    except KeyError:
        return 0
    except ValueError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    if end == -1:
        end = None
    elif end is not None:
        end += 1

    ba = bitarray.bitarray()
    ba.frombytes(obj.get_bytes()[start:end])
    return ba.count()
示例#18
0
def ltrim_handler(client, argv):
    '''
    Trim an existing list so that it will contain only the specified range of elements specified.
    Both start and stop are zero-based indexes, where 0 is the first element of the list (the head),
    1 the next element and so on.

    For example: LTRIM foobar 0 2 will modify the list stored at foobar so that only the first three
    elements of the list will remain.

    start and end can also be negative numbers indicating offsets from the end of the list, where -1 is
    the last element of the list, -2 the penultimate element and so on.

    Out of range indexes will not produce an error: if start is larger than the end of the list, or
    start > end, the result will be an empty list (which causes key to be removed). If end is larger
    than the end of the list, Redis will treat it like the last element of the list.

    .. code::
        LTRIM key start stop

    '''

    key, start, stop = argv[1], argv[2], argv[3]

    try:
        start = int(start)
        stop = int(stop)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return True
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    if start < 0:
        start = len(obj) + start
    if stop < 0:
        stop = len(obj) + stop

    obj.value = obj[start:stop]
    return True
示例#19
0
def decrby_handler(client, argv):
    '''
    Decrements the number stored at key by decrement. If the key does not exist, it is set to 0
    before performing the operation. An error is returned if the key contains a value of the wrong
    type or contains a string that can not be represented as integer. This operation is limited to
    64 bit signed integers.

    See INCR for extra information on increment/decrement operations.

    .. code::
        DECRBY key decrement

    :return: the value of key after the decrement
    :rtype: int

    '''

    key, decrement = argv[1], argv[2]

    try:
        decrement = int(decrement)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
        value = obj.get_integer()
    except KeyError:
        value = 0
        obj = RedisStringObject(value)
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        value = obj.get_integer()
    except ValueError:
        abort(message='value is not an integer or out of range')

    value -= decrement

    obj.value = value
    # client.db.key_space[key] = obj
    return obj
示例#20
0
def linsert(client, argv):
    '''
    Inserts value in the list stored at key either before or after the reference value pivot.

    When key does not exist, it is considered an empty list and no operation is performed.

    An error is returned when key exists but does not hold a list value.

    .. code::
        LINSERT key BEFORE|AFTER pivot value

    :return: the length of the list after the insert operation, or -1 when the value pivot was not found.
    :rtype: int

    '''

    key, op, pivot, value = argv[1], argv[2].upper(), argv[3], argv[4]

    if op not in (b'BEFORE', b'AFTER'):
        abort(message='syntax error')

    if op == b'BEFORE':
        op_func = lambda index: index
    else:
        op_func = lambda index: index + 1

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return None
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    try:
        index = obj.index(pivot)
        obj.insert(op_func(index), value)
    except ValueError:
        return None

    return len(obj)
示例#21
0
def setbit_handler(client, argv):
    '''
    Sets or clears the bit at offset in the string value stored at key.

    The bit is either set or cleared depending on value, which can be either 0 or 1.
    When key does not exist, a new string value is created. The string is grown to make
    sure it can hold a bit at offset. The offset argument is required to be greater than
    or equal to 0, and smaller than 232 (this limits bitmaps to 512MB). When the string
    at key is grown, added bits are set to 0.

    .. code::
        SETBIT key offset value

    '''

    key, offset, value = argv[1], argv[2], argv[3]
    if key in client.db.key_space and not isinstance(client.db.key_space[key], RedisStringObject):
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        offset = int(offset)
        value = int(value)
    except ValueError:
        abort(message='bit offset is not an integer or out of range')

    ba = bitarray.bitarray()

    try:
        obj = get_object(client.db, key, RedisStringObject)
        ba.frombytes(obj.get_bytes())
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')
    except KeyError:
        pass

    if len(ba) < offset:
        ba.extend([0] * (offset - len(ba) + 1))

    ba[offset] = value
    client.db.key_space[key].value = ba.tobytes()
    return True
示例#22
0
def incr_handler(client, argv):
    '''
    Increments the number stored at key by one. If the key does not exist, it is set to 0 before
    performing the operation. An error is returned if the key contains a value of the wrong type or
    contains a string that can not be represented as integer. This operation is limited to 64 bit
    signed integers.

    Note: this is a string operation because Redis does not have a dedicated integer type. The string
    stored at the key is interpreted as a base-10 64 bit signed integer to execute the operation.

    Redis stores integers in their integer representation, so for string values that actually hold an
    integer, there is no overhead for storing the string representation of the integer.

    .. code::
        INCR key

    :return: the value of key after the increment
    :rtype: int

    '''
    key = argv[1]

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
        value = obj.get_integer()
    except KeyError:
        value = 0
        obj = RedisStringObject(value)
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        value = obj.get_integer()
    except ValueError:
        abort(message='value is not an integer or out of range')

    value += 1

    obj.value = value
    client.db.key_space[key] = obj
    return obj
示例#23
0
def llen_handler(client, argv):
    '''
    Returns the length of the list stored at key. If key does not exist, it is interpreted as an empty
    list and 0 is returned. An error is returned when the value stored at key is not a list.

    .. code::
        LLEN key

    :return: the length of the list at key.
    :rtype: int
    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    return len(obj)
示例#24
0
def linsert(client, argv):
    '''
    Inserts value in the list stored at key either before or after the reference value pivot.

    When key does not exist, it is considered an empty list and no operation is performed.

    An error is returned when key exists but does not hold a list value.

    .. code::
        LINSERT key BEFORE|AFTER pivot value

    :return: the length of the list after the insert operation, or -1 when the value pivot was not found.
    :rtype: int

    '''

    key, op, pivot, value = argv[1], argv[2].upper(), argv[3], argv[4]

    if op not in (b'BEFORE', b'AFTER'):
        abort(message='syntax error')

    if op == b'BEFORE':
        op_func = lambda index: index
    else:
        op_func = lambda index: index + 1

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return None
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        index = obj.index(pivot)
        obj.insert(op_func(index), value)
    except ValueError:
        return None

    return len(obj)
示例#25
0
def setrange_handler(client, argv):
    '''
    Overwrites part of the string stored at key, starting at the specified offset, for the entire
    length of value. If the offset is larger than the current length of the string at key, the string
    is padded with zero-bytes to make offset fit. Non-existing keys are considered as empty strings,
    so this command will make sure it holds a string large enough to be able to set value at offset.

    Note that the maximum offset that you can set is 229 -1 (536870911), as Redis Strings are limited
    to 512 megabytes. If you need to grow beyond this size, you can use multiple keys.

    .. code::
        SETRANGE key offset value

    :return: the length of the string after it was modified by the command.
    :rtype: int

    '''

    key, offset, value = argv[1], argv[2], argv[3]
    try:
        offset = int(offset)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisStringObject)
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')
    except KeyError:
        obj = RedisStringObject()

    stor_value = obj.get_bytes()
    if len(stor_value) < offset:
        stor_value += bytes(offset - len(stor_value)) + value
    else:
        stor_value = stor_value[0:offset + 1] + value

    obj.value = stor_value
    client.db.key_space[key] = obj
    return len(stor_value)
示例#26
0
def strlen_handler(client, argv):
    '''
    Returns the length of the string value stored at key. An error is returned when key holds a non-string value.

    .. code::
        STRLEN key

    :return: the length of the string at key, or 0 when key does not exist.
    :rtype: int

    '''

    key = argv[1]

    try:
        obj = get_object(client.db, key, type=RedisStringObject)
    except KeyError:
        return 0
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    return len(obj.get_bytes())
示例#27
0
def lrange_handler(client, argv):
    '''
    Returns the specified elements of the list stored at key. The offsets start and stop are zero-based
    indexes, with 0 being the first element of the list (the head of the list), 1 being the next element
    and so on.

    These offsets can also be negative numbers indicating offsets starting at the end of the list. For
    example, -1 is the last element of the list, -2 the penultimate, and so on.

    .. code::
        LRANGE key start stop

    :return: list of elements in the specified range.
    :rtype: list

    '''

    key, start, stop = argv[1], argv[2], argv[3]
    try:
        start = int(start)
        stop = int(stop)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return []
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    if start < 0:
        start = len(obj) + start
    if stop < 0:
        stop = len(obj) + stop

    return obj[start:stop + 1]
示例#28
0
def mget_handler(client, argv):
    '''
    Returns the values of all specified keys. For every key that does not hold a string value or does
    not exist, the special value nil is returned. Because of this, the operation never fails.

    .. code::
        MGET key [key ...]

    :return: list of values at the specified keys.
    :rtype: list

    '''

    result = []
    for key in argv[1:]:
        try:
            obj = get_object(client.db, key, RedisStringObject)
            result.append(obj)
        except (TypeError, KeyError):
            result.append(None)

    return result
示例#29
0
def llen_handler(client, argv):
    '''
    Returns the length of the list stored at key. If key does not exist, it is interpreted as an empty
    list and 0 is returned. An error is returned when the value stored at key is not a list.

    .. code::
        LLEN key

    :return: the length of the list at key.
    :rtype: int
    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    return len(obj)
示例#30
0
def lrange_handler(client, argv):
    '''
    Returns the specified elements of the list stored at key. The offsets start and stop are zero-based
    indexes, with 0 being the first element of the list (the head of the list), 1 being the next element
    and so on.

    These offsets can also be negative numbers indicating offsets starting at the end of the list. For
    example, -1 is the last element of the list, -2 the penultimate, and so on.

    .. code::
        LRANGE key start stop

    :return: list of elements in the specified range.
    :rtype: list

    '''

    key, start, stop = argv[1], argv[2], argv[3]
    try:
        start = int(start)
        stop = int(stop)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return []
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    if start < 0:
        start = len(obj) + start
    if stop < 0:
        stop = len(obj) + stop

    return obj[start:stop + 1]
示例#31
0
def expire_handler(client, argv):
    '''
    Set a timeout on key. After the timeout has expired, the key will automatically be deleted. A key
    with an associated timeout is often said to be volatile in Redis terminology.

    The timeout is cleared only when the key is removed using the DEL command or overwritten using the
    SET or GETSET commands. This means that all the operations that conceptually alter the value stored
    at the key without replacing it with a new one will leave the timeout untouched. For instance,
    incrementing the value of a key with INCR, pushing a new value into a list with LPUSH, or altering the
    field value of a hash with HSET are all operations that will leave the timeout untouched.

    The timeout can also be cleared, turning the key back into a persistent key, using the PERSIST command.

    If a key is renamed with RENAME, the associated time to live is transferred to the new key name.

    If a key is overwritten by RENAME, like in the case of an existing key Key_A that is overwritten by a call
    like RENAME Key_B Key_A, it does not matter if the original Key_A had a timeout associated or not, the new
    key Key_A will inherit all the characteristics of Key_B.

    .. code::
        EXPIRE key time
    '''

    key, exptime = argv[1], argv[2]
    try:
        exptime = int(exptime)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key)
    except KeyError:
        return 0

    obj.expire_time = time.time() + exptime
    return 1
示例#32
0
def pexpire_handler(client, argv):
    '''
    This command works exactly like EXPIRE but the time to live of the key is specified in milliseconds
    instead of seconds.

    .. code::
        PEXPIRE key milliseconds

    '''

    key, milliseconds = argv[1], argv[2]

    try:
        milliseconds = int(milliseconds)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key)
    except KeyError:
        return 0

    obj.expire_time = time.time() + milliseconds / 1000.0
    return 1
示例#33
0
def pexpireat_handler(client, argv):
    '''
    PEXPIREAT has the same effect and semantic as EXPIREAT, but the Unix time at which the key will
    expire is specified in milliseconds instead of seconds.

    .. code::
        PEXPIREAT key milliseconds-timestamp

    '''

    key, milliseconds = argv[1], argv[2]

    try:
        milliseconds = int(milliseconds)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key)
    except KeyError:
        return 0

    obj.expire_time = milliseconds / 1000.0
    return 1
示例#34
0
def lpushx_handler(client, argv):
    '''
    Inserts value at the head of the list stored at key, only if key already exists and holds a list.
    In contrary to LPUSH, no operation will be performed when key does not yet exist.

    .. code::
        LPUSHX key value

    :return: the length of the list after the push operation.
    :rtype: int

    '''

    key, value = argv[1], argv[2]

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    obj.push(value)
    return len(obj)
示例#35
0
def lpop_handler(client, argv):
    '''
    Removes and returns the first element of the list stored at key.

    .. code::
        LPOP key

    :return: the value of the first element, or nil when key does not exist.
    :rtype: str

    '''

    key = argv[1]
    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return 0
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    try:
        return obj.pop()
    except IndexError:
        return None
示例#36
0
def lset_handler(client, argv):
    '''

    Sets the list element at index to value. For more information on the index argument, see LINDEX.

    An error is returned for out of range indexes.

    .. code::
        LSET key index value

    '''

    key, index, value = argv[1], argv[2], argv[3]

    try:
        index = int(index)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        abort(message='index out of range')
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    if index < 0:
        index = len(obj) + index

    try:
        obj[index] = value
    except IndexError:
        abort(message='index out of range')
    return True
示例#37
0
def lpush_handler(client, argv):
    '''
    Insert all the specified values at the head of the list stored at key. If key does not exist,
    it is created as empty list before performing the push operations. When key holds a value that
    is not a list, an error is returned.

    It is possible to push multiple elements using a single command call just specifying multiple
    arguments at the end of the command. Elements are inserted one after the other to the head of
    the list, from the leftmost element to the rightmost element. So for instance the command LPUSH
    mylist a b c will result into a list containing c as first element, b as second element and a
    as third element.

    .. code::
        LPUSH key value [value ...]

    :return: the length of the list after the push operations.
    :rtype: int

    '''

    key, values = argv[1], argv[2:]

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        obj = RedisListObject()
        client.db.key_space[key] = obj
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    # for value in values:
    obj.push(*values)

    return len(obj)
示例#38
0
def lindex_handler(client, argv):
    '''
    Returns the element at index index in the list stored at key. The index is zero-based, so 0
    means the first element, 1 the second element and so on. Negative indices can be used to designate
    elements starting at the tail of the list. Here, -1 means the last element, -2 means the penultimate
    and so forth.

    When the value at key is not a list, an error is returned.

    .. code::
        LINDEX key index

    :return: the requested element, or nil when index is out of range.
    :rtype: str

    '''

    key, index = argv[1], argv[2]
    try:
        index = int(index)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, RedisListObject)
    except KeyError:
        return None
    except TypeError:
        abort(
            errtype='WRONGTYPE',
            message='Operation against a key holding the wrong kind of value')

    try:
        return obj[index]
    except IndexError:
        return None
示例#39
0
def getrange_handler(client, argv):
    '''
    Returns the substring of the string value stored at key, determined by the offsets start and end
    (both are inclusive). Negative offsets can be used in order to provide an offset starting from the
    end of the string. So -1 means the last character, -2 the penultimate and so forth.

    The function handles out of range requests by limiting the resulting range to the actual length of
    the string.

    .. code::
        GETRANGE key start end

    '''

    key, start, end = argv[1], argv[2], argv[3]

    try:
        start = int(start)
        end = int(end)
    except ValueError:
        abort(message='value is not an integer or out of range')

    try:
        obj = get_object(client.db, key, type=RedisStringObject)

    except KeyError:
        return b''
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    length = len(obj)
    if start < 0:
        start = length + start
    if end < 0:
        end = length + end
    return obj.get_range(start, end)
示例#40
0
def bitop_handler(client, argv):
    '''
    Perform a bitwise operation between multiple keys (containing string values) and store the result in
    the destination key.

    The BITOP command supports four bitwise operations: AND, OR, XOR and NOT, thus the valid forms to call
    the command are:

    * BITOP AND destkey srckey1 srckey2 srckey3 ... srckeyN
    * BITOP OR destkey srckey1 srckey2 srckey3 ... srckeyN
    * BITOP XOR destkey srckey1 srckey2 srckey3 ... srckeyN
    * BITOP NOT destkey srckey

    As you can see NOT is special as it only takes an input key, because it performs inversion of bits so it
    only makes sense as an unary operator.

    The result of the operation is always stored at destkey.

    .. code::
        BITOP operation destkey key [key ...]

    :return: The size of the string stored in the destination key, that is equal to the size of the longest
             input string.
    :rtype: int

    '''

    operation, destkey, keys = argv[1].upper(), argv[2], argv[3:]
    print(operation, destkey, keys)
    if operation not in (b'AND', b'OR', b'XOR', b'NOT'):
        abort(message='Don\'t know what to do for "bitop"')

    if operation == b'NOT':
        if len(keys) > 1:
            abort(message='BITOP NOT must be called with a single source key.')

        try:
            obj = get_object(client.db, keys[0], RedisStringObject)
        except KeyError:
            return 0
        except TypeError:
            abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

        ba = bitarray.bitarray()
        ba.frombytes(obj.get_bytes())
        ba.invert()
        client.db.key_space[destkey] = RedisStringObject(ba.tobytes())
        return len(client.db.key_space[destkey].value)

    if operation == b'AND':
        oper_func = lambda a, b: a & b
    elif operation == b'OR':
        oper_func = lambda a, b: a | b
    elif operation == b'XOR':
        oper_func = lambda a, b: a ^ b

    dest_ba = bitarray.bitarray()
    try:
        obj = get_object(client.db, keys[0], RedisStringObject)
        dest_ba.frombytes(obj.get_bytes())
    except KeyError:
        pass
    except TypeError:
        abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

    for key in keys[1:]:
        try:
            obj = get_object(client.db, key, RedisStringObject)
            src_ba = bitarray.bitarray()
            src_ba.frombytes(obj.get_bytes())

            if len(src_ba) > len(dest_ba):
                dest_ba = bitarray.bitarray('0' * (len(src_ba) - len(dest_ba))) + dest_ba
            elif len(dest_ba) > len(src_ba):
                src_ba = bitarray.bitarray('0' * (len(dest_ba) - len(src_ba))) + src_ba
        except KeyError:
            src_ba = bitarray.bitarray('0' * len(dest_ba))
        except TypeError:
            abort(errtype='WRONGTYPE', message='Operation against a key holding the wrong kind of value')

        dest_ba = oper_func(dest_ba, src_ba)

    client.db.key_space[destkey] = RedisStringObject(dest_ba.tobytes())
    return len(client.db.key_space[destkey].get_bytes())