diff options
Diffstat (limited to 'redis/old_client.py')
-rwxr-xr-x | redis/old_client.py | 1359 |
1 files changed, 0 insertions, 1359 deletions
diff --git a/redis/old_client.py b/redis/old_client.py deleted file mode 100755 index 14343e2..0000000 --- a/redis/old_client.py +++ /dev/null @@ -1,1359 +0,0 @@ -#!/usr/bin/env python - -""" redis.py - A client for the Redis daemon. - -History: - - 20091207 Redis conenctions are now thread safe. Thanks Aaron Raddon - - 20091115 implemented __getitem__, __setitem__, __delitem__ to make - gets/sets/deletes easy and pythonic. better py 2.6 decimal support - (thanks Brent Pedersen) - - 20091106 added SPOP, SCARD, SRANDMEMBER, SDIFF, SDIFFSTORE - and all sorted set (Z*) commands (Andy McCurdy) - - 20091106 added connection retry handling when the client gets disconnected, - perhaps via the server timing the client out. - - 20090603 fix missing errno import, add sunion and sunionstore commands, - generalize shebang (Jochen Kupperschmidt) - -""" - -__author__ = "Ludovico Magnocavallo <ludo\x40qix\x2eit>" -__copyright__ = "Copyright 2009, Ludovico Magnocavallo" -__license__ = "MIT" -__version__ = "0.6.1" -__revision__ = "$LastChangedRevision: 175 $"[22:-2] -__date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18:-2] - - -# TODO: Redis._get_multi_response - - -import socket -import decimal -import errno -import threading -import warnings - -from redis import exceptions - -# global threading manager -connections = threading.local() - -class Redis(object): - """The main Redis client. - - >>> r = Redis(db=9) - >>> r['a'] = 24.0 - >>> r['a'] - Decimal("24.0") - - >>> r = Redis(db=9, float_fn=float) - >>> r['a'] - 24.0 - - >>> del r['a'] - >>> print r.get('a') # r['a'] will raise KeyError - None - - """ - - def __init__(self, host=None, port=None, timeout=None, - db=None, nodelay=None, charset='utf8', errors='strict', - retry_connection=True, float_fn=decimal.Decimal): - self.host = host or 'localhost' - self.port = port or 6379 - self.db = db - self.connection_key = '%s:%s:%s' % (self.host, self.port, self.db) - if timeout: - socket.setdefaulttimeout(timeout) - self.nodelay = nodelay - self.charset = charset - self.errors = errors - self.float_fn = float_fn - if retry_connection: - self.send_command = self._send_command_retry - else: - self.send_command = self._send_command - self.retry_connection = retry_connection - self._sock = None - self._fp = None - - - def _encode(self, s): - if isinstance(s, str): - return s - if isinstance(s, unicode): - try: - return s.encode(self.charset, self.errors) - except UnicodeEncodeError, e: - raise exceptions.InvalidData("Error encoding unicode value '%s': %s" % (value.encode(self.charset, 'replace'), e)) - return str(s) - - def _send_command(self, s): - """ - >>> r = Redis(db=9) - >>> r.connect() - >>> r._sock.close() - >>> try: - ... r._send_command('pippo') - ... except exceptions.ConnectionError, e: - ... print e - Error 9 while writing to socket. Bad file descriptor. - >>> - >>> - """ - self.connect() - try: - self._sock.sendall(s) - except socket.error, e: - if e.args[0] == 32: - # broken pipe - self.disconnect() - raise exceptions.ConnectionError("Error %s while writing to socket. %s." % tuple(e.args)) - return self._get_response() - - def _send_command_retry(self, s): - try: - return self._send_command(s) - except exceptions.ConnectionError: - self.disconnect() - return self._send_command(s) - - - def _read(self): - try: - return self._fp.readline() - except socket.error, e: - if e.args and e.args[0] == errno.EAGAIN: - return - self.disconnect() - raise exceptions.ConnectionError("Error %s while reading from socket. %s." % tuple(e.args)) - if not data: - self.disconnect() - raise exceptions.ConnectionError("Socket connection closed when reading.") - return data - - def ping(self): - """ - >>> r = Redis(db=9) - >>> r.ping() - 'PONG' - >>> - """ - return self.send_command('PING\r\n') - - def set(self, name, value, preserve=False, getset=False): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo') - 'OK' - >>> r.set('a', u'pippo \u3235') - 'OK' - >>> r.get('a') - u'pippo \u3235' - >>> r.set('b', 105.2) - 'OK' - >>> r.set('b', 'xxx', preserve=True) - 0 - >>> r.get('b') - Decimal("105.2") - >>> - """ - # the following will raise an error for unicode values that can't be encoded to ascii - # we could probably add an 'encoding' arg to init, but then what do we do with get()? - # convert back to unicode? and what about ints, or pickled values? - if getset: command = 'GETSET' - elif preserve: command = 'SETNX' - else: command = 'SET' - value = self._encode(value) - return self.send_command('%s %s %s\r\n%s\r\n' % ( - command, name, len(value), value - )) - - __setitem__ = set - - def get(self, name): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n') - ('OK', 'OK', 'OK', 'OK') - >>> r.get('a') - u'pippo' - >>> r.get('b') - 15 - >>> r.get('d') - u'\\r\\n' - >>> r.get('b') - 15 - >>> r.get('c') - u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' - >>> r.get('c') - u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' - >>> r.get('ajhsd') - """ - return self.send_command('GET %s\r\n' % name) - - def __getitem__(self, name): - val = self.get(name) - if val is None: - raise KeyError - return val - - - def getset(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo') - 'OK' - >>> r.getset('a', 2) - u'pippo' - >>> - """ - return self.set(name, value, getset=True) - - def mget(self, *args): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n') - ('OK', 'OK', 'OK', 'OK') - >>> r.mget('a', 'b', 'c', 'd') - [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n'] - >>> - """ - return self.send_command('MGET %s\r\n' % ' '.join(args)) - - def incr(self, name, amount=1): - """ - >>> r = Redis(db=9) - >>> r.delete('a') - 1 - >>> r.incr('a') - 1 - >>> r.incr('a') - 2 - >>> r.incr('a', 2) - 4 - >>> - """ - if amount == 1: - return self.send_command('INCR %s\r\n' % name) - else: - return self.send_command('INCRBY %s %s\r\n' % (name, amount)) - - def decr(self, name, amount=1): - """ - >>> r = Redis(db=9) - >>> if r.get('a'): - ... r.delete('a') - ... else: - ... print 1 - 1 - >>> r.decr('a') - -1 - >>> r.decr('a') - -2 - >>> r.decr('a', 5) - -7 - >>> - """ - if amount == 1: - return self.send_command('DECR %s\r\n' % name) - else: - return self.send_command('DECRBY %s %s\r\n' % (name, amount)) - - def exists(self, name): - """ - >>> r = Redis(db=9) - >>> r.exists('dsjhfksjdhfkdsjfh') - 0 - >>> r.set('a', 'a') - 'OK' - >>> r.exists('a') - 1 - >>> - """ - return self.send_command('EXISTS %s\r\n' % name) - - def delete(self, *args): - """ - >>> r = Redis(db=9) - >>> r.delete('dsjhfksjdhfkdsjfh') - 0 - >>> r.set('a', 'a') - 'OK' - >>> r.delete('a') - 1 - >>> r.exists('a') - 0 - >>> r.delete('a') - 0 - >>> r.set('a', 'a') - 'OK' - >>> r.set('b', 'b') - 'OK' - >>> r.delete('a', 'b') - 2 - >>> r.exists('a') - 0 - >>> r.exists('b') - 0 - >>> - """ - return self.send_command('DEL %s\r\n' % ' '.join(args)) - - __delitem__ = delete - - def get_type(self, name): - """ - >>> r = Redis(db=9) - >>> r.set('a', 3) - 'OK' - >>> r.get_type('a') - 'string' - >>> r.get_type('zzz') - >>> - """ - res = self.send_command('TYPE %s\r\n' % name) - if res == 'none': - return - return res - - def keys(self, pattern): - """ - >>> r = Redis(db=9) - >>> r.flush() - 'OK' - >>> r.set('a', 'a') - 'OK' - >>> r.keys('a*') - [u'a'] - >>> r.set('a2', 'a') - 'OK' - >>> keys = r.keys('a*') - >>> u'a' in keys - True - >>> u'a2' in keys - True - >>> r.delete('a2') - 1 - >>> r.keys('sjdfhskjh*') - [] - >>> - """ - return self.send_command('KEYS %s\r\n' % pattern).split() - - def randomkey(self): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'a') - 'OK' - >>> isinstance(r.randomkey(), str) - True - >>> - """ - #raise NotImplementedError("Implemented but buggy, do not use.") - return self.send_command('RANDOMKEY\r\n') - - def rename(self, src, dst, preserve=False): - """ - >>> r = Redis(db=9) - >>> try: - ... r.rename('a', 'a') - ... except exceptions.ResponseError, e: - ... print e - source and destination objects are the same - >>> r.rename('a', 'b') - 'OK' - >>> try: - ... r.rename('a', 'b') - ... except exceptions.ResponseError, e: - ... print e - no such key - >>> r.set('a', 1) - 'OK' - >>> r.rename('b', 'a', preserve=True) - 0 - >>> - """ - if preserve: - return self.send_command('RENAMENX %s %s\r\n' % (src, dst)) - else: - return self.send_command('RENAME %s %s\r\n' % (src, dst)) - - def dbsize(self): - """ - >>> r = Redis(db=9) - >>> type(r.dbsize()) - <type 'int'> - >>> - """ - return self.send_command('DBSIZE\r\n') - - def ttl(self, name): - """ - >>> r = Redis(db=9) - >>> r.ttl('a') - -1 - >>> r.expire('a', 10) - 1 - >>> r.ttl('a') - 10 - >>> r.expire('a', 0) - 0 - >>> - """ - return self.send_command('TTL %s\r\n' % name) - - def expire(self, name, time): - """ - >>> r = Redis(db=9) - >>> r.set('a', 1) - 'OK' - >>> r.expire('a', 1) - 1 - >>> r.expire('zzzzz', 1) - 0 - >>> - """ - return self.send_command('EXPIRE %s %s\r\n' % (name, time)) - - def push(self, name, value, head=False, **kwargs): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.set('a', 'a') - 'OK' - >>> try: - ... r.push('a', 'a') - ... except exceptions.ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> - """ - if "tail" in kwargs: - tail = kwargs.pop("tail") - warnings.warn(DeprecationWarning( - "tail argument of push is deprecated, use head=False")) - head = not tail - if kwargs: - raise TypeError( - "push() got an unexpected keyword argument: %s" % ( - kwargs.keys()[0])) - - value = self._encode(value) - command = 'RPUSH' - if head: command = 'LPUSH' - return self.send_command('%s %s %s\r\n%s\r\n' \ - % (command, name, len(value), value)) - - def llen(self, name): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.llen('l') - 1 - >>> r.push('l', 'a') - 'OK' - >>> r.llen('l') - 2 - >>> - """ - return self.send_command('LLEN %s\r\n' % name) - - def lrange(self, name, start, end): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.lrange('l', 0, 1) - [] - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrange('l', 0, 1) - [u'aaa'] - >>> r.push('l', 'bbb') - 'OK' - >>> r.lrange('l', 0, 0) - [u'aaa'] - >>> r.lrange('l', 0, 1) - [u'aaa', u'bbb'] - >>> r.lrange('l', -1, 0) - [] - >>> r.lrange('l', -1, -1) - [u'bbb'] - >>> - """ - return self.send_command('LRANGE %s %s %s\r\n' % (name, start, end)) - - def ltrim(self, name, start, end): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.ltrim('l', 0, 1) - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.push('l', 'ccc') - 'OK' - >>> r.ltrim('l', 0, 1) - 'OK' - >>> r.llen('l') - 2 - >>> r.ltrim('l', 99, 95) - 'OK' - >>> r.llen('l') - 0 - >>> - """ - return self.send_command('LTRIM %s %s %s\r\n' % (name, start, end)) - - def lindex(self, name, index): - """ - >>> r = Redis(db=9) - >>> res = r.delete('l') - >>> r.lindex('l', 0) - >>> r.push('l', 'aaa') - 'OK' - >>> r.lindex('l', 0) - u'aaa' - >>> r.lindex('l', 2) - >>> r.push('l', 'ccc') - 'OK' - >>> r.lindex('l', 1) - u'ccc' - >>> r.lindex('l', -1) - u'ccc' - >>> - """ - return self.send_command('LINDEX %s %s\r\n' % (name, index)) - - def pop(self, name, tail=False): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.pop('l') - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.pop('l') - u'aaa' - >>> r.pop('l') - u'bbb' - >>> r.pop('l') - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.pop('l', tail=True) - u'bbb' - >>> r.pop('l') - u'aaa' - >>> r.pop('l') - >>> - """ - command = 'LPOP' - if tail: command = 'RPOP' - return self.send_command('%s %s\r\n' % (command, name)) - - def poppush(self, src, dst): - """ - >>> r = Redis(db=9) - >>> r.delete('lsource') - 0 - >>> r.delete('ldestination') - 0 - >>> r.push('lsource', 'one', head=True) - 'OK' - >>> r.push('lsource', 'two', head=True) - 'OK' - >>> r.push('lsource', 'three', head=True) - 'OK' - >>> r.poppush('lsource', 'ldestination') - u'one' - >>> r.lrange('lsource', 0, -1) - [u'three', u'two'] - >>> r.lrange('ldestination', 0, -1) - [u'one'] - >>> r.poppush('lsource', 'ldestination') - u'two' - >>> r.lrange('lsource', 0, -1) - [u'three'] - >>> r.lrange('ldestination', 0, -1) - [u'two', u'one'] - """ - return self.send_command('RPOPLPUSH %s %s\r\n%s\r\n' % ( - src, len(dst), dst - )) - - def lset(self, name, index, value): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> try: - ... r.lset('l', 0, 'a') - ... except exceptions.ResponseError, e: - ... print e - no such key - >>> r.push('l', 'aaa') - 'OK' - >>> try: - ... r.lset('l', 1, 'a') - ... except exceptions.ResponseError, e: - ... print e - index out of range - >>> r.lset('l', 0, 'bbb') - 'OK' - >>> r.lrange('l', 0, 1) - [u'bbb'] - >>> - """ - value = self._encode(value) - return self.send_command('LSET %s %s %s\r\n%s\r\n' % ( - name, index, len(value), value - )) - - def lrem(self, name, value, num=0): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrem('l', 'aaa') - 2 - >>> r.lrange('l', 0, 10) - [u'bbb'] - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.lrem('l', 'aaa', 1) - 1 - >>> r.lrem('l', 'aaa', 1) - 1 - >>> r.lrem('l', 'aaa', 1) - 0 - >>> - """ - value = self._encode(value) - return self.send_command('LREM %s %s %s\r\n%s\r\n' % ( - name, num, len(value), value - )) - - def sort(self, name, by=None, get=None, start=None, num=None, desc=False, alpha=False): - """ - >>> r = Redis(db=9) - >>> r.delete('l') - 1 - >>> r.push('l', 'ccc') - 'OK' - >>> r.push('l', 'aaa') - 'OK' - >>> r.push('l', 'ddd') - 'OK' - >>> r.push('l', 'bbb') - 'OK' - >>> r.sort('l', alpha=True) - [u'aaa', u'bbb', u'ccc', u'ddd'] - >>> r.delete('l') - 1 - >>> for i in range(1, 5): - ... res = r.push('l', 1.0 / i) - >>> r.sort('l') - [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")] - >>> r.sort('l', desc=True) - [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")] - >>> r.sort('l', desc=True, start=2, num=1) - [Decimal("0.333333333333")] - >>> r.set('weight_0.5', 10) - 'OK' - >>> r.sort('l', desc=True, by='weight_*') - [Decimal("0.5"), Decimal("1.0"), Decimal("0.333333333333"), Decimal("0.25")] - >>> for i in r.sort('l', desc=True): - ... res = r.set('test_%s' % i, 100 - float(i)) - >>> r.sort('l', desc=True, get='test_*') - [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")] - >>> r.sort('l', desc=True, by='weight_*', get='test_*') - [Decimal("99.5"), Decimal("99.0"), Decimal("99.6666666667"), Decimal("99.75")] - >>> r.sort('l', desc=True, by='weight_*', get='missing_*') - [None, None, None, None] - >>> - """ - stmt = ['SORT', name] - if by: - stmt.append("BY %s" % by) - if start is not None and num is not None: - stmt.append("LIMIT %s %s" % (start, num)) - if get is None: - pass - elif isinstance(get, basestring): - stmt.append("GET %s" % get) - elif isinstance(get, list) or isinstance(get, tuple): - for g in get: - stmt.append("GET %s" % g) - else: - raise exceptions.RedisError("Invalid parameter 'get' for Redis sort") - if desc: - stmt.append("DESC") - if alpha: - stmt.append("ALPHA") - return self.send_command(' '.join(stmt + ["\r\n"])) - - def sadd(self, name, value): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s') - >>> r.sadd('s', 'a') - 1 - >>> r.sadd('s', 'b') - 1 - >>> - """ - value = self._encode(value) - return self.send_command('SADD %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - - def srem(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.srem('s', 'aaa') - 0 - >>> r.sadd('s', 'b') - 1 - >>> r.srem('s', 'b') - 1 - >>> r.sismember('s', 'b') - 0 - >>> - """ - value = self._encode(value) - return self.send_command('SREM %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - - def spop(self, name): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s') - >>> r.sadd('s', 'a') - 1 - >>> r.spop('s') - u'a' - """ - return self.send_command('SPOP %s\r\n' % name) - - def smove(self, src, dst, member): - """ - >>> r = Redis(db=9) - >>> _ = r.delete('s1') - >>> _ = r.delete('s2') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'b') - 1 - >>> r.smove('s1', 's2', 'a') - 1 - >>> src_set = r.smembers('s1') - >>> 'a' in src_set - False - >>> dst_set = r.smembers('s2') - >>> 'a' in dst_set - True - >>> 'b' in dst_set - True - """ - return self.send_command('SMOVE %s %s %s\r\n%s\r\n' % ( - src, dst, len(member), member - )) - - def scard(self, name): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s') - >>> r.sadd('s', 'a') - 1 - >>> r.scard('s') - 1 - """ - return self.send_command('SCARD %s\r\n' % name) - - def sismember(self, name, value): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.sismember('s', 'b') - 0 - >>> r.sadd('s', 'a') - 1 - >>> r.sismember('s', 'b') - 0 - >>> r.sismember('s', 'a') - 1 - >>> - """ - value = self._encode(value) - return self.send_command('SISMEMBER %s %s\r\n%s\r\n' % ( - name, len(value), value - )) - - def sinter(self, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> try: - ... r.sinter() - ... except exceptions.ResponseError, e: - ... print e - wrong number of arguments for 'sinter' command - >>> try: - ... r.sinter('l') - ... except exceptions.ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> r.sinter('s1', 's2', 's3') - set([]) - >>> r.sinter('s1', 's2') - set([u'a']) - >>> - """ - return set(self.send_command('SINTER %s\r\n' % ' '.join(args))) - - def sinterstore(self, dest, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sinterstore('s_s', 's1', 's2', 's3') - 0 - >>> r.sinterstore('s_s', 's1', 's2') - 1 - >>> r.smembers('s_s') - set([u'a']) - >>> - """ - return self.send_command('SINTERSTORE %s %s\r\n' % (dest, ' '.join(args))) - - def smembers(self, name): - """ - >>> r = Redis(db=9) - >>> r.delete('s') - 1 - >>> r.sadd('s', 'a') - 1 - >>> r.sadd('s', 'b') - 1 - >>> try: - ... r.smembers('l') - ... except exceptions.ResponseError, e: - ... print e - Operation against a key holding the wrong kind of value - >>> r.smembers('s') - set([u'a', u'b']) - >>> - """ - return set(self.send_command('SMEMBERS %s\r\n' % name)) - - def sunion(self, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sunion('s1', 's2', 's3') - set([u'a', u'b']) - >>> r.sadd('s2', 'c') - 1 - >>> r.sunion('s1', 's2', 's3') - set([u'a', u'c', u'b']) - >>> - """ - return set(self.send_command('SUNION %s\r\n' % ' '.join(args))) - - def sunionstore(self, dest, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s2', 'a') - 1 - >>> r.sadd('s3', 'b') - 1 - >>> r.sunionstore('s4', 's1', 's2', 's3') - 2 - >>> r.smembers('s4') - set([u'a', u'b']) - >>> - """ - return self.send_command('SUNIONSTORE %s %s\r\n' % (dest, ' '.join(args))) - - def sdiff(self, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> r.sadd('s1', 'x') - 1 - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s1', 'b') - 1 - >>> r.sadd('s1', 'c') - 1 - >>> r.sadd('s2', 'c') - 1 - >>> r.sadd('s3', 'a') - 1 - >>> r.sadd('s3', 'd') - 1 - >>> diff = r.sdiff('s1', 's2', 's3') - >>> 'x' in diff - True - >>> 'b' in diff - True - """ - return set(self.send_command('SDIFF %s\r\n' % ' '.join(args))) - - def sdiffstore(self, dest, *args): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> res = r.delete('s2') - >>> res = r.delete('s3') - >>> res = r.delete('s4') - >>> r.sadd('s1', 'x') - 1 - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s1', 'b') - 1 - >>> r.sadd('s1', 'c') - 1 - >>> r.sadd('s2', 'c') - 1 - >>> r.sadd('s3', 'a') - 1 - >>> r.sadd('s3', 'd') - 1 - >>> r.sdiffstore('s4', 's1', 's2', 's3') - 2 - >>> diff = r.smembers('s4') - >>> 'x' in diff - True - >>> 'b' in diff - True - """ - return self.send_command('SDIFFSTORE %s %s\r\n' % (dest, ' '.join(args))) - - def srandmember(self, key): - """ - >>> r = Redis(db=9) - >>> res = r.delete('s1') - >>> r.sadd('s1', 'a') - 1 - >>> r.sadd('s1', 'b') - 1 - >>> rand = r.srandmember('s1') - >>> rand in ['a', 'b'] - True - """ - return self.send_command('SRANDMEMBER %s\r\n' % key) - - def zadd(self, key, member, score): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> r.zadd('z1', 'abc', 5) - 1 - >>> r.zadd('z1', 'def', 3) - 1 - >>> r.zadd('z1', 'abc', 2) - 0 - """ - member = self._encode(member) - return self.send_command('ZADD %s %s %s\r\n%s\r\n' % ( - key, score, len(member), member - )) - - def zrem(self, key, member): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> r.zadd('z1', 'abc', 5) - 1 - >>> r.zrem('z1', 'abc') - 1 - >>> r.zrem('z1', 'def') - 0 - """ - member = self._encode(member) - return self.send_command('ZREM %s %s\r\n%s\r\n' % ( - key, len(member), member - )) - - def zrange(self, key, start, end, desc=False, withscores=False): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> r.zadd('z1', 'a', 5) - 1 - >>> r.zadd('z1', 'b', 2) - 1 - >>> r.zadd('z1', 'c', 7) - 1 - >>> r.zrange('z1', 0, 2) - [u'b', u'a', u'c'] - >>> r.zrange('z1', 0, 1) - [u'b', u'a'] - >>> r.zrange('z1', 0, 2, desc=True) - [u'c', u'a', u'b'] - >>> r.zrange('z1', 0, 1, desc=True) - [u'c', u'a'] - >>> - """ - command = 'ZRANGE' - if desc: command = 'ZREVRANGE' - _withscores = withscores and ' withscores' or '' - return self.send_command('%s %s %s %s %s\r\n' \ - % (command, key, start, end, _withscores)) - - def zrangebyscore(self, key, min, max, offset=None, count=None): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> r.zadd('z1', 'a', 5) - 1 - >>> r.zadd('z1', 'b', 2) - 1 - >>> r.zadd('z1', 'c', 7) - 1 - >>> r.zadd('z1', 'd', 10) - 1 - >>> r.zrangebyscore('z1', 5, 7) - [u'a', u'c'] - >>> r.zadd('z1', 'e', 8) - 1 - >>> r.zrangebyscore('z1', 5, 8, offset=0, count=2) - [u'a', u'c'] - >>> r.zrangebyscore('z1', 5, 8, offset=1, count=2) - [u'c', u'e'] - """ - if offset is not None and count is not None: - limit = " LIMIT %d %d" % (offset, count) - else: - limit = "" - - return self.send_command('ZRANGEBYSCORE %s %s %s%s\r\n' % ( - key, min, max, limit - )) - - def zcard(self, key): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> res = r.delete('z2') - >>> r.zadd('z1', 'a', 5) - 1 - >>> r.zadd('z1', 'b', 2) - 1 - >>> r.zadd('z1', 'c', 7) - 1 - >>> r.zcard('z1') - 3 - >>> r.zcard('z2') - 0 - """ - return self.send_command('ZCARD %s\r\n' % key) - - def zscore(self, key, member): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> res = r.delete('z2') - >>> r.zadd('z1', 'a', 5) - 1 - >>> r.zscore('z1', 'a') - 5 - >>> r.zscore('z1', 'b') - >>> r.zscore('z2', 'a') - """ - member = self._encode(member) - return self.send_command('ZSCORE %s %s\r\n%s\r\n' % ( - key, len(member), member - )) - - def zincr(self, key, member, value=1): - """ - >>> r = Redis(db=9) - >>> res = r.delete('z1') - >>> r.zincr('z1', 'k1') - 1 - >>> r.zincr('z1', 'k1', 5) - 6 - >>> r.zincr('z1', 'k1', -4) - 2 - """ - member = self._encode(member) - return self.send_command('ZINCRBY %s %s %s\r\n%s\r\n' % ( - key, value, len(member), member - )) - - def select(self, db): - """ - >>> r = Redis(db=9) - >>> r.delete('a') - 1 - >>> r.select(10) - 'OK' - >>> r.set('a', 1) - 'OK' - >>> r.select(9) - 'OK' - >>> r.get('a') - >>> - """ - return self.send_command('SELECT %s\r\n' % db) - - def move(self, name, db): - """ - >>> r = Redis(db=9) - >>> r.set('a', 'a') - 'OK' - >>> r.select(10) - 'OK' - >>> if r.get('a'): - ... r.delete('a') - ... else: - ... print 1 - 1 - >>> r.select(9) - 'OK' - >>> r.move('a', 10) - 1 - >>> r.get('a') - >>> r.select(10) - 'OK' - >>> r.get('a') - u'a' - >>> r.select(9) - 'OK' - >>> - """ - return self.send_command('MOVE %s %s\r\n' % (name, db)) - - def save(self, background=False): - """ - >>> r = Redis(db=9) - >>> r.save() - 'OK' - >>> r.save(background=True) - 'Background saving started' - >>> - """ - if background: - return self.send_command('BGSAVE\r\n') - else: - return self.send_command('SAVE\r\n') - - def shutdown(self): - """Close all client connections, dump database and quit the server.""" - try: - self.send_command('SHUTDOWN\r\n') - except exceptions.ConnectionError: - return - - def lastsave(self): - """ - >>> import time - >>> r = Redis(db=9) - >>> t = int(time.time()) - >>> r.save() - 'OK' - >>> r.lastsave() >= t - True - >>> - """ - return self.send_command('LASTSAVE\r\n') - - def flush(self, all_dbs=False): - """ - >>> r = Redis(db=9) - >>> r.flush() - 'OK' - >>> # r.flush(all_dbs=True) - >>> - """ - command = 'FLUSHDB' - if all_dbs: command = 'FLUSHALL' - return self.send_command('%s\r\n' % command) - - def info(self): - """ - >>> r = Redis(db=9) - >>> info = r.info() - >>> info and isinstance(info, dict) - True - >>> isinstance(info.get('connected_clients'), int) - True - >>> - """ - info = dict() - for l in self.send_command('INFO\r\n').split('\r\n'): - if not l: - continue - k, v = l.split(':', 1) - if v.isdigit(): - info[k] = int(v) - else: - info[k] = v - return info - - def auth(self, passwd): - return self.send_command('AUTH %s\r\n' % passwd) - - def _get_response(self): - data = self._read().strip() - if not data: - self.disconnect() - raise exceptions.ConnectionError("Socket closed on remote end") - c = data[0] - if c == '-': - err = data[1:] - if data[:5] == '-ERR ': - err = data[5:] - raise exceptions.ResponseError(err) - if c == '+': - return data[1:] - if c == '*': - try: - num = int(data[1:]) - except (TypeError, ValueError): - raise exceptions.InvalidResponse("Cannot convert multi-response header '%s' to integer" % data) - return [self._get_value() for i in range(num)] - return self._get_value(data) - - def _get_value(self, data=None): - data = data or self._read().strip() - if data == '$-1': - return None - try: - if not "." in data: - value = int(data[1:]) - else: - value = float(data[1:]) - c, i = data[0], value - except ValueError: - raise exceptions.InvalidResponse("Cannot convert data '%s' to integer" % data) - if c == ':': - return i - if c != '$': - raise exceptions.InvalidResponse("Unkown response prefix for '%s'" % data) - buf = [] - while i >= 0: - data = self._read() - i -= len(data) - buf.append(data) - - data = ''.join(buf)[:-2] - try: - if not '.' in data: - value = int(data) - else: - value = self.float_fn(data) - return value - except (ValueError, decimal.InvalidOperation): - return data.decode(self.charset) - - def disconnect(self): - if self._sock is not None: - try: - self._sock.close() - except socket.error: - pass - self._sock = None - self._fp = None - if hasattr(connections, self.connection_key): - delattr(connections, self.connection_key) - - def connect(self): - """ - >>> import socket - >>> r = Redis(db=9) - >>> r.connect() - >>> isinstance(r._sock, socket.socket) - True - >>> r.disconnect() - >>> - """ - if isinstance(self._sock, socket.socket): - return - try: - # connection pooling to thread local - if not hasattr(connections, self.connection_key): - sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) - sock.connect((self.host, self.port)) - if self.nodelay is not None: - sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, self.nodelay) - setattr(connections, self.connection_key, sock) - sock = getattr(connections, self.connection_key) - except socket.error, e: - raise exceptions.ConnectionError("Error %s connecting to %s:%s. %s." % (e.args[0], self.host, self.port, e.args[1])) - else: - # no exceptions - self._sock = sock - self._fp = self._sock.makefile('r') - if self.db: - self.select(self.db) - - -def run_doctests(module=None): - # hack to make doctests pass in 2.6 - decimal.Decimal.__repr__ = lambda self: 'Decimal("%s")' % str(self) - import doctest - doctest.testmod(m=module) - -if __name__ == '__main__': - run_doctests() |