]>
git.saurik.com Git - redis.git/blob - client-libraries/python/redis.py
f0e4cd45b8334b7ab96cf516face140a7dd99143
   3 """ redis.py - A client for the Redis daemon. 
   7 __author__ 
= "Ludovico Magnocavallo <ludo\x40qix\x2eit>" 
   8 __copyright__ 
= "Copyright 2009, Ludovico Magnocavallo" 
  11 __revision__ 
= "$LastChangedRevision: 175 $"[22:-2] 
  12 __date__ 
= "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18:-2] 
  15 # TODO: Redis._get_multi_response 
  25 class RedisError(Exception): pass 
  26 class ConnectionError(RedisError
): pass 
  27 class ResponseError(RedisError
): pass 
  28 class InvalidResponse(RedisError
): pass 
  29 class InvalidData(RedisError
): pass 
  33     """The main Redis client. 
  36     def __init__(self
, host
=None, port
=None, timeout
=None, db
=None, nodelay
=None, charset
='utf8', errors
='strict'): 
  37         self
.host 
= host 
or 'localhost' 
  38         self
.port 
= port 
or 6379 
  40             socket
.setdefaulttimeout(timeout
) 
  41         self
.nodelay 
= nodelay
 
  42         self
.charset 
= charset
 
  49         if isinstance(s
, str): 
  51         if isinstance(s
, unicode): 
  53                 return s
.encode(self
.charset
, self
.errors
) 
  54             except UnicodeEncodeError, e
: 
  55                 raise InvalidData("Error encoding unicode value '%s': %s" % (value
.encode(self
.charset
, 'replace'), e
)) 
  65         ... except ConnectionError, e: 
  67         Error 9 while writing to socket. Bad file descriptor. 
  73         except socket
.error
, e
: 
  77             raise ConnectionError("Error %s while writing to socket. %s." % tuple(e
.args
)) 
  81             return self
._fp
.readline() 
  82         except socket
.error
, e
: 
  83             if e
.args 
and e
.args
[0] == errno
.EAGAIN
: 
  86             raise ConnectionError("Error %s while reading from socket. %s." % tuple(e
.args
)) 
  89             raise ConnectionError("Socket connection closed when reading.") 
 100         self
._write
('PING\r\n') 
 101         return self
.get_response() 
 103     def set(self
, name
, value
, preserve
=False, getset
=False): 
 106         >>> r.set('a', 'pippo') 
 108         >>> r.set('a', u'pippo \u3235') 
 112         >>> r.set('b', 105.2) 
 114         >>> r.set('b', 'xxx', preserve=True) 
 121         # the following will raise an error for unicode values that can't be encoded to ascii 
 122         # we could probably add an 'encoding' arg to init, but then what do we do with get()? 
 123         # convert back to unicode? and what about ints, or pickled values? 
 124         if getset
: command 
= 'GETSET' 
 125         elif preserve
: command 
= 'SETNX' 
 126         else: command 
= 'SET' 
 127         value 
= self
._encode
(value
) 
 128         self
._write
('%s %s %s\r\n%s\r\n' % ( 
 129                 command
, name
, len(value
), value
 
 131         return self
.get_response() 
 136         >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n') 
 137         ('OK', 'OK', 'OK', 'OK') 
 147         u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' 
 149         u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' 
 154         self
._write
('GET %s\r\n' % name
) 
 155         return self
.get_response() 
 157     def getset(self
, name
, value
): 
 160         >>> r.set('a', 'pippo') 
 166         return self
.set(name
, value
, getset
=True) 
 168     def mget(self
, *args
): 
 171         >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n') 
 172         ('OK', 'OK', 'OK', 'OK') 
 173         >>> r.mget('a', 'b', 'c', 'd') 
 174         [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n'] 
 178         self
._write
('MGET %s\r\n' % ' '.join(args
)) 
 179         return self
.get_response() 
 181     def incr(self
, name
, amount
=1): 
 196             self
._write
('INCR %s\r\n' % name
) 
 198             self
._write
('INCRBY %s %s\r\n' % (name
, amount
)) 
 199         return self
.get_response() 
 201     def decr(self
, name
, amount
=1): 
 219             self
._write
('DECR %s\r\n' % name
) 
 221             self
._write
('DECRBY %s %s\r\n' % (name
, amount
)) 
 222         return self
.get_response() 
 224     def exists(self
, name
): 
 227         >>> r.exists('dsjhfksjdhfkdsjfh') 
 236         self
._write
('EXISTS %s\r\n' % name
) 
 237         return self
.get_response() 
 239     def delete(self
, name
): 
 242         >>> r.delete('dsjhfksjdhfkdsjfh') 
 255         self
._write
('DEL %s\r\n' % name
) 
 256         return self
.get_response() 
 258     def get_type(self
, name
): 
 265         >>> r.get_type('zzz') 
 269         self
._write
('TYPE %s\r\n' % name
) 
 270         res 
= self
.get_response() 
 271         return None if res 
== 'none' else res
 
 273     def keys(self
, pattern
): 
 288         >>> r.keys('sjdfhskjh*') 
 293         self
._write
('KEYS %s\r\n' % pattern
) 
 294         return self
.get_response().split() 
 301         >>> isinstance(r.randomkey(), str) 
 305         #raise NotImplementedError("Implemented but buggy, do not use.") 
 307         self
._write
('RANDOMKEY\r\n') 
 308         return self
.get_response() 
 310     def rename(self
, src
, dst
, preserve
=False): 
 314         ...     r.rename('a', 'a') 
 315         ... except ResponseError, e: 
 317         source and destination objects are the same 
 318         >>> r.rename('a', 'b') 
 321         ...     r.rename('a', 'b') 
 322         ... except ResponseError, e: 
 327         >>> r.rename('b', 'a', preserve=True) 
 333             self
._write
('RENAMENX %s %s\r\n' % (src
, dst
)) 
 334             return self
.get_response() 
 336             self
._write
('RENAME %s %s\r\n' % (src
, dst
)) 
 337             return self
.get_response() #.strip() 
 347         self
._write
('DBSIZE\r\n') 
 348         return self
.get_response() 
 355         >>> r.expire('a', 10) 
 364         self
._write
('TTL %s\r\n' % name
) 
 365         return self
.get_response() 
 367     def expire(self
, name
, time
): 
 374         >>> r.expire('zzzzz', 1) 
 379         self
._write
('EXPIRE %s %s\r\n' % (name
, time
)) 
 380         return self
.get_response() 
 382     def push(self
, name
, value
, tail
=False): 
 393         ... except ResponseError, e: 
 395         Operation against a key holding the wrong kind of value 
 399         value 
= self
._encode
(value
) 
 400         self
._write
('%s %s %s\r\n%s\r\n' % ( 
 401             'LPUSH' if tail 
else 'RPUSH', name
, len(value
), value
 
 403         return self
.get_response() 
 405     def llen(self
, name
): 
 421         self
._write
('LLEN %s\r\n' % name
) 
 422         return self
.get_response() 
 424     def lrange(self
, name
, start
, end
): 
 429         >>> r.lrange('l', 0, 1) 
 431         >>> r.push('l', 'aaa') 
 433         >>> r.lrange('l', 0, 1) 
 435         >>> r.push('l', 'bbb') 
 437         >>> r.lrange('l', 0, 0) 
 439         >>> r.lrange('l', 0, 1) 
 441         >>> r.lrange('l', -1, 0) 
 443         >>> r.lrange('l', -1, -1) 
 448         self
._write
('LRANGE %s %s %s\r\n' % (name
, start
, end
)) 
 449         return self
.get_response() 
 451     def ltrim(self
, name
, start
, end
): 
 457         ...     r.ltrim('l', 0, 1) 
 458         ... except ResponseError, e: 
 461         >>> r.push('l', 'aaa') 
 463         >>> r.push('l', 'bbb') 
 465         >>> r.push('l', 'ccc') 
 467         >>> r.ltrim('l', 0, 1) 
 471         >>> r.ltrim('l', 99, 95) 
 478         self
._write
('LTRIM %s %s %s\r\n' % (name
, start
, end
)) 
 479         return self
.get_response() 
 481     def lindex(self
, name
, index
): 
 484         >>> res = r.delete('l') 
 486         >>> r.push('l', 'aaa') 
 491         >>> r.push('l', 'ccc') 
 495         >>> r.lindex('l', -1) 
 500         self
._write
('LINDEX %s %s\r\n' % (name
, index
)) 
 501         return self
.get_response() 
 503     def pop(self
, name
, tail
=False): 
 509         >>> r.push('l', 'aaa') 
 511         >>> r.push('l', 'bbb') 
 518         >>> r.push('l', 'aaa') 
 520         >>> r.push('l', 'bbb') 
 522         >>> r.pop('l', tail=True) 
 530         self
._write
('%s %s\r\n' % ('RPOP' if tail 
else 'LPOP', name
)) 
 531         return self
.get_response() 
 533     def lset(self
, name
, index
, value
): 
 539         ...     r.lset('l', 0, 'a') 
 540         ... except ResponseError, e: 
 543         >>> r.push('l', 'aaa') 
 546         ...     r.lset('l', 1, 'a') 
 547         ... except ResponseError, e: 
 550         >>> r.lset('l', 0, 'bbb') 
 552         >>> r.lrange('l', 0, 1) 
 557         value 
= self
._encode
(value
) 
 558         self
._write
('LSET %s %s %s\r\n%s\r\n' % ( 
 559             name
, index
, len(value
), value
 
 561         return self
.get_response() 
 563     def lrem(self
, name
, value
, num
=0): 
 568         >>> r.push('l', 'aaa') 
 570         >>> r.push('l', 'bbb') 
 572         >>> r.push('l', 'aaa') 
 574         >>> r.lrem('l', 'aaa') 
 576         >>> r.lrange('l', 0, 10) 
 578         >>> r.push('l', 'aaa') 
 580         >>> r.push('l', 'aaa') 
 582         >>> r.lrem('l', 'aaa', 1) 
 584         >>> r.lrem('l', 'aaa', 1) 
 586         >>> r.lrem('l', 'aaa', 1) 
 591         value 
= self
._encode
(value
) 
 592         self
._write
('LREM %s %s %s\r\n%s\r\n' % ( 
 593             name
, num
, len(value
), value
 
 595         return self
.get_response() 
 597     def sort(self
, name
, by
=None, get
=None, start
=None, num
=None, desc
=False, alpha
=False): 
 602         >>> r.push('l', 'ccc') 
 604         >>> r.push('l', 'aaa') 
 606         >>> r.push('l', 'ddd') 
 608         >>> r.push('l', 'bbb') 
 610         >>> r.sort('l', alpha=True) 
 611         [u'aaa', u'bbb', u'ccc', u'ddd'] 
 614         >>> for i in range(1, 5): 
 615         ...     res = r.push('l', 1.0 / i) 
 617         [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")] 
 618         >>> r.sort('l', desc=True) 
 619         [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")] 
 620         >>> r.sort('l', desc=True, start=2, num=1) 
 621         [Decimal("0.333333333333")] 
 622         >>> r.set('weight_0.5', 10) 
 624         >>> r.sort('l', desc=True, by='weight_*') 
 625         [Decimal("0.5"), Decimal("1.0"), Decimal("0.333333333333"), Decimal("0.25")] 
 626         >>> for i in r.sort('l', desc=True): 
 627         ...     res = r.set('test_%s' % i, 100 - float(i)) 
 628         >>> r.sort('l', desc=True, get='test_*') 
 629         [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")] 
 630         >>> r.sort('l', desc=True, by='weight_*', get='test_*') 
 631         [Decimal("99.5"), Decimal("99.0"), Decimal("99.6666666667"), Decimal("99.75")] 
 632         >>> r.sort('l', desc=True, by='weight_*', get='missing_*') 
 633         [None, None, None, None] 
 636         stmt 
= ['SORT', name
] 
 638             stmt
.append("BY %s" % by
) 
 640             stmt
.append("LIMIT %s %s" % (start
, num
)) 
 643         elif isinstance(get
, basestring
): 
 644             stmt
.append("GET %s" % get
) 
 645         elif isinstance(get
, list) or isinstance(get
, tuple): 
 647                 stmt
.append("GET %s" % g
) 
 649             raise RedisError("Invalid parameter 'get' for Redis sort") 
 655         self
._write
(' '.join(stmt 
+ ["\r\n"])) 
 656         return self
.get_response() 
 658     def sadd(self
, name
, value
): 
 661         >>> res = r.delete('s') 
 669         value 
= self
._encode
(value
) 
 670         self
._write
('SADD %s %s\r\n%s\r\n' % ( 
 671             name
, len(value
), value
 
 673         return self
.get_response() 
 675     def srem(self
, name
, value
): 
 680         >>> r.srem('s', 'aaa') 
 686         >>> r.sismember('s', 'b') 
 691         value 
= self
._encode
(value
) 
 692         self
._write
('SREM %s %s\r\n%s\r\n' % ( 
 693             name
, len(value
), value
 
 695         return self
.get_response() 
 697     def sismember(self
, name
, value
): 
 702         >>> r.sismember('s', 'b') 
 706         >>> r.sismember('s', 'b') 
 708         >>> r.sismember('s', 'a') 
 713         value 
= self
._encode
(value
) 
 714         self
._write
('SISMEMBER %s %s\r\n%s\r\n' % ( 
 715             name
, len(value
), value
 
 717         return self
.get_response() 
 719     def sinter(self
, *args
): 
 722         >>> res = r.delete('s1') 
 723         >>> res = r.delete('s2') 
 724         >>> res = r.delete('s3') 
 725         >>> r.sadd('s1', 'a') 
 727         >>> r.sadd('s2', 'a') 
 729         >>> r.sadd('s3', 'b') 
 733         ... except ResponseError, e: 
 735         wrong number of arguments 
 738         ... except ResponseError, e: 
 740         Operation against a key holding the wrong kind of value 
 741         >>> r.sinter('s1', 's2', 's3') 
 743         >>> r.sinter('s1', 's2') 
 748         self
._write
('SINTER %s\r\n' % ' '.join(args
)) 
 749         return set(self
.get_response()) 
 751     def sinterstore(self
, dest
, *args
): 
 754         >>> res = r.delete('s1') 
 755         >>> res = r.delete('s2') 
 756         >>> res = r.delete('s3') 
 757         >>> r.sadd('s1', 'a') 
 759         >>> r.sadd('s2', 'a') 
 761         >>> r.sadd('s3', 'b') 
 763         >>> r.sinterstore('s_s', 's1', 's2', 's3') 
 765         >>> r.sinterstore('s_s', 's1', 's2') 
 767         >>> r.smembers('s_s') 
 772         self
._write
('SINTERSTORE %s %s\r\n' % (dest
, ' '.join(args
))) 
 773         return self
.get_response() 
 775     def smembers(self
, name
): 
 786         ... except ResponseError, e: 
 788         Operation against a key holding the wrong kind of value 
 794         self
._write
('SMEMBERS %s\r\n' % name
) 
 795         return set(self
.get_response()) 
 797     def select(self
, db
): 
 812         self
._write
('SELECT %s\r\n' % db
) 
 813         return self
.get_response() 
 815     def move(self
, name
, db
): 
 841         self
._write
('MOVE %s %s\r\n' % (name
, db
)) 
 842         return self
.get_response() 
 844     def save(self
, background
=False): 
 850         ...     resp = r.save(background=True) 
 851         ... except ResponseError, e: 
 852         ...     assert str(e) == 'background save already in progress', str(e) 
 854         ...     assert resp == 'OK' 
 859             self
._write
('BGSAVE\r\n') 
 861             self
._write
('SAVE\r\n') 
 862         return self
.get_response() 
 868         >>> t = int(time.time()) 
 871         >>> r.lastsave() >= t 
 876         self
._write
('LASTSAVE\r\n') 
 877         return self
.get_response() 
 879     def flush(self
, all_dbs
=False): 
 884         >>> # r.flush(all_dbs=True) 
 888         self
._write
('%s\r\n' % ('FLUSHALL' if all_dbs 
else 'FLUSHDB')) 
 889         return self
.get_response() 
 895         >>> info and isinstance(info, dict) 
 897         >>> isinstance(info.get('connected_clients'), int) 
 902         self
._write
('INFO\r\n') 
 904         for l 
in self
.get_response().split('\r\n'): 
 907             k
, v 
= l
.split(':', 1) 
 908             info
[k
] = int(v
) if v
.isdigit() else v
 
 911     def auth(self
, passwd
): 
 913         self
._write
('AUTH %s\r\n' % passwd
) 
 914         return self
.get_response() 
 916     def get_response(self
): 
 917         data 
= self
._read
().strip() 
 920             raise ConnectionError("Socket closed on remote end") 
 923             raise ResponseError(data
[5:] if data
[:5] == '-ERR ' else data
[1:]) 
 929             except (TypeError, ValueError): 
 930                 raise InvalidResponse("Cannot convert multi-response header '%s' to integer" % data
) 
 933                 result
.append(self
._get
_value
()) 
 935         return self
._get
_value
(data
) 
 937     def _get_value(self
, data
=None): 
 938         data 
= data 
or self
._read
().strip() 
 942             c
, i 
= data
[0], (int(data
[1:]) if data
.find('.') == -1 else float(data
[1:])) 
 944             raise InvalidResponse("Cannot convert data '%s' to integer" % data
) 
 948             raise InvalidResponse("Unkown response prefix for '%s'" % data
) 
 956         data 
= ''.join(buf
)[:-2] 
 958             return int(data
) if data
.find('.') == -1 else decimal
.Decimal(data
) 
 959         except (ValueError, decimal
.InvalidOperation
): 
 960             return data
.decode(self
.charset
) 
 962     def disconnect(self
): 
 963         if isinstance(self
._sock
, socket
.socket
): 
 975         >>> isinstance(r._sock, socket.socket) 
 980         if isinstance(self
._sock
, socket
.socket
): 
 983             sock 
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
) 
 984             sock
.connect((self
.host
, self
.port
)) 
 985         except socket
.error
, e
: 
 986             raise ConnectionError("Error %s connecting to %s:%s. %s." % (e
.args
[0], self
.host
, self
.port
, e
.args
[1])) 
 989             self
._fp 
= self
._sock
.makefile('r') 
 992             if self
.nodelay 
is not None: 
 993                 self
._sock
.setsockopt(socket
.SOL_TCP
, socket
.TCP_NODELAY
, self
.nodelay
) 
 996 if __name__ 
== '__main__':