]>
git.saurik.com Git - redis.git/blob - client-libraries/python/redis.py
   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 
  24 class RedisError(Exception): pass 
  25 class ConnectionError(RedisError
): pass 
  26 class ResponseError(RedisError
): pass 
  27 class InvalidResponse(RedisError
): pass 
  28 class InvalidData(RedisError
): pass 
  32     """The main Redis client. 
  35     def __init__(self
, host
=None, port
=None, timeout
=None, db
=None): 
  36         self
.host 
= host 
or 'localhost' 
  37         self
.port 
= port 
or 6379 
  39             socket
.setdefaulttimeout(timeout
) 
  51         ... except ConnectionError, e: 
  53         Error 9 while writing to socket. Bad file descriptor. 
  59         except socket
.error
, e
: 
  63             raise ConnectionError("Error %s while writing to socket. %s." % tuple(e
.args
)) 
  67             return self
._fp
.readline() 
  68         except socket
.error
, e
: 
  69             if e
.args 
and e
.args
[0] == errno
.EAGAIN
: 
  72             raise ConnectionError("Error %s while reading from socket. %s." % tuple(e
.args
)) 
  75             raise ConnectionError("Socket connection closed when reading.") 
  86         self
._write
('PING\r\n') 
  87         return self
.get_response() 
  89     def set(self
, name
, value
, preserve
=False): 
  92         >>> r.set('a', 'pippo') 
  95         ...     r.set('a', u'pippo \u3235') 
  96         ... except InvalidData, e: 
  98         Error encoding unicode value for key 'a': 'ascii' codec can't encode character u'\u3235' in position 15: ordinal not in range(128). 
 101         >>> r.set('b', 'xxx', preserve=True) 
 108         # the following will raise an error for unicode values that can't be encoded to ascii 
 109         # we could probably add an 'encoding' arg to init, but then what do we do with get()? 
 110         # convert back to unicode? and what about ints, or pickled values? 
 112             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 113             self
._write
('%s %s %s\r\n%s\r\n' % ( 
 114                 'SETNX' if preserve 
else 'SET', name
, len(value
), value
 
 116         except UnicodeEncodeError, e
: 
 117             raise InvalidData("Error encoding unicode value for key '%s': %s." % (name
, e
)) 
 118         return self
.get_response() 
 123         >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n') 
 124         ('OK', 'OK', 'OK', 'OK') 
 134         ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' 
 136         ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n ' 
 141         self
._write
('GET %s\r\n' % name
) 
 142         return self
.get_response() 
 144     def mget(self
, *args
): 
 147         >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n') 
 148         ('OK', 'OK', 'OK', 'OK') 
 149         >>> r.mget('a', 'b', 'c', 'd') 
 150         ['pippo', '15', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', '\\r\\n'] 
 154         self
._write
('MGET %s\r\n' % ' '.join(args
)) 
 155         return self
.get_response() 
 157     def incr(self
, name
, amount
=1): 
 172             self
._write
('INCR %s\r\n' % name
) 
 174             self
._write
('INCRBY %s %s\r\n' % (name
, amount
)) 
 175         return self
.get_response() 
 177     def decr(self
, name
, amount
=1): 
 195             self
._write
('DECR %s\r\n' % name
) 
 197             self
._write
('DECRBY %s %s\r\n' % (name
, amount
)) 
 198         return self
.get_response() 
 200     def exists(self
, name
): 
 203         >>> r.exists('dsjhfksjdhfkdsjfh') 
 212         self
._write
('EXISTS %s\r\n' % name
) 
 213         return self
.get_response() 
 215     def delete(self
, name
): 
 218         >>> r.delete('dsjhfksjdhfkdsjfh') 
 231         self
._write
('DEL %s\r\n' % name
) 
 232         return self
.get_response() 
 234     def key_type(self
, name
): 
 239         self
._write
('TYPE %s\r\n' % name
) 
 240         return self
.get_response() 
 242     def keys(self
, pattern
): 
 257         >>> r.keys('sjdfhskjh*') 
 262         self
._write
('KEYS %s\r\n' % pattern
) 
 263         return self
.get_response().split() 
 270         >>> isinstance(r.randomkey(), str) 
 274         #raise NotImplementedError("Implemented but buggy, do not use.") 
 276         self
._write
('RANDOMKEY\r\n') 
 277         return self
.get_response() 
 279     def rename(self
, src
, dst
, preserve
=False): 
 283         ...     r.rename('a', 'a') 
 284         ... except ResponseError, e: 
 286         source and destination objects are the same 
 287         >>> r.rename('a', 'b') 
 290         ...     r.rename('a', 'b') 
 291         ... except ResponseError, e: 
 296         >>> r.rename('b', 'a', preserve=True) 
 302             self
._write
('RENAMENX %s %s\r\n' % (src
, dst
)) 
 303             return self
.get_response() 
 305             self
._write
('RENAME %s %s\r\n' % (src
, dst
)) 
 306             return self
.get_response() #.strip() 
 308     def push(self
, name
, value
, tail
=False): 
 319         ... except ResponseError, e: 
 321         Operation against a key holding the wrong kind of value 
 325         # same considerations on unicode as in set() apply here 
 327             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 328             self
._write
('%s %s %s\r\n%s\r\n' % ( 
 329                 'LPUSH' if tail 
else 'RPUSH', name
, len(value
), value
 
 331         except UnicodeEncodeError, e
: 
 332             raise InvalidData("Error encoding unicode value for element in list '%s': %s." % (name
, e
)) 
 333         return self
.get_response() 
 335     def llen(self
, name
): 
 351         self
._write
('LLEN %s\r\n' % name
) 
 352         return self
.get_response() 
 354     def lrange(self
, name
, start
, end
): 
 359         >>> r.lrange('l', 0, 1) 
 361         >>> r.push('l', 'aaa') 
 363         >>> r.lrange('l', 0, 1) 
 365         >>> r.push('l', 'bbb') 
 367         >>> r.lrange('l', 0, 0) 
 369         >>> r.lrange('l', 0, 1) 
 371         >>> r.lrange('l', -1, 0) 
 373         >>> r.lrange('l', -1, -1) 
 378         self
._write
('LRANGE %s %s %s\r\n' % (name
, start
, end
)) 
 379         return self
.get_response() 
 381     def ltrim(self
, name
, start
, end
): 
 387         ...     r.ltrim('l', 0, 1) 
 388         ... except ResponseError, e: 
 391         >>> r.push('l', 'aaa') 
 393         >>> r.push('l', 'bbb') 
 395         >>> r.push('l', 'ccc') 
 397         >>> r.ltrim('l', 0, 1) 
 401         >>> r.ltrim('l', 99, 95) 
 408         self
._write
('LTRIM %s %s %s\r\n' % (name
, start
, end
)) 
 409         return self
.get_response() 
 411     def lindex(self
, name
, index
): 
 414         >>> res = r.delete('l') 
 416         >>> r.push('l', 'aaa') 
 421         >>> r.push('l', 'ccc') 
 425         >>> r.lindex('l', -1) 
 430         self
._write
('LINDEX %s %s\r\n' % (name
, index
)) 
 431         return self
.get_response() 
 433     def pop(self
, name
, tail
=False): 
 439         >>> r.push('l', 'aaa') 
 441         >>> r.push('l', 'bbb') 
 448         >>> r.push('l', 'aaa') 
 450         >>> r.push('l', 'bbb') 
 452         >>> r.pop('l', tail=True) 
 460         self
._write
('%s %s\r\n' % ('RPOP' if tail 
else 'LPOP', name
)) 
 461         return self
.get_response() 
 463     def lset(self
, name
, index
, value
): 
 469         ...     r.lset('l', 0, 'a') 
 470         ... except ResponseError, e: 
 473         >>> r.push('l', 'aaa') 
 476         ...     r.lset('l', 1, 'a') 
 477         ... except ResponseError, e: 
 480         >>> r.lset('l', 0, 'bbb') 
 482         >>> r.lrange('l', 0, 1) 
 488             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 489             self
._write
('LSET %s %s %s\r\n%s\r\n' % ( 
 490                 name
, index
, len(value
), value
 
 492         except UnicodeEncodeError, e
: 
 493             raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index
, name
, e
)) 
 494         return self
.get_response() 
 496     def lrem(self
, name
, value
, num
=0): 
 501         >>> r.push('l', 'aaa') 
 503         >>> r.push('l', 'bbb') 
 505         >>> r.push('l', 'aaa') 
 507         >>> r.lrem('l', 'aaa') 
 509         >>> r.lrange('l', 0, 10) 
 511         >>> r.push('l', 'aaa') 
 513         >>> r.push('l', 'aaa') 
 515         >>> r.lrem('l', 'aaa', 1) 
 517         >>> r.lrem('l', 'aaa', 1) 
 519         >>> r.lrem('l', 'aaa', 1) 
 525             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 526             self
._write
('LREM %s %s %s\r\n%s\r\n' % ( 
 527                 name
, num
, len(value
), value
 
 529         except UnicodeEncodeError, e
: 
 530             raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index
, name
, e
)) 
 531         return self
.get_response() 
 533     def sort(self
, name
, by
=None, get
=None, start
=None, num
=None, desc
=False, alpha
=False): 
 538         >>> r.push('l', 'ccc') 
 540         >>> r.push('l', 'aaa') 
 542         >>> r.push('l', 'ddd') 
 544         >>> r.push('l', 'bbb') 
 546         >>> r.sort('l', alpha=True) 
 547         ['aaa', 'bbb', 'ccc', 'ddd'] 
 550         >>> for i in range(1, 5): 
 551         ...     res = r.push('l', 1.0 / i) 
 553         ['0.25', '0.333333333333', '0.5', '1.0'] 
 554         >>> r.sort('l', desc=True) 
 555         ['1.0', '0.5', '0.333333333333', '0.25'] 
 556         >>> r.sort('l', desc=True, start=2, num=1) 
 558         >>> r.set('weight_0.5', 10) 
 560         >>> r.sort('l', desc=True, by='weight_*') 
 561         ['0.5', '1.0', '0.333333333333', '0.25'] 
 562         >>> for i in r.sort('l', desc=True): 
 563         ...     res = r.set('test_%s' % i, 100 - float(i)) 
 564         >>> r.sort('l', desc=True, get='test_*') 
 565         ['99.0', '99.5', '99.6666666667', '99.75'] 
 566         >>> r.sort('l', desc=True, by='weight_*', get='test_*') 
 567         ['99.5', '99.0', '99.6666666667', '99.75'] 
 568         >>> r.sort('l', desc=True, by='weight_*', get='missing_*') 
 569         [None, None, None, None] 
 572         stmt 
= ['SORT', name
] 
 574             stmt
.append("BY %s" % by
) 
 576             stmt
.append("LIMIT %s %s" % (start
, num
)) 
 579         elif isinstance(get
, basestring
): 
 580             stmt
.append("GET %s" % get
) 
 581         elif isinstance(get
, list) or isinstance(get
, tuple): 
 583                 stmt
.append("GET %s" % g
) 
 585             raise RedisError("Invalid parameter 'get' for Redis sort") 
 591         self
._write
(' '.join(stmt 
+ ["\r\n"])) 
 592         return self
.get_response() 
 594     def sadd(self
, name
, value
): 
 597         >>> res = r.delete('s') 
 605         # same considerations on unicode as in set() apply here 
 607             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 608             self
._write
('SADD %s %s\r\n%s\r\n' % ( 
 609                 name
, len(value
), value
 
 611         except UnicodeEncodeError, e
: 
 612             raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name
, e
)) 
 613         return self
.get_response() 
 615     def srem(self
, name
, value
): 
 620         >>> r.srem('s', 'aaa') 
 626         >>> r.sismember('s', 'b') 
 631         # same considerations on unicode as in set() apply here 
 633             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 634             self
._write
('SREM %s %s\r\n%s\r\n' % ( 
 635                 name
, len(value
), value
 
 637         except UnicodeEncodeError, e
: 
 638             raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name
, e
)) 
 639         return self
.get_response() 
 641     def sismember(self
, name
, value
): 
 646         >>> r.sismember('s', 'b') 
 650         >>> r.sismember('s', 'b') 
 652         >>> r.sismember('s', 'a') 
 657         # same considerations on unicode as in set() apply here 
 659             value 
= value 
if isinstance(value
, basestring
) else str(value
) 
 660             self
._write
('SISMEMBER %s %s\r\n%s\r\n' % ( 
 661                 name
, len(value
), value
 
 663         except UnicodeEncodeError, e
: 
 664             raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name
, e
)) 
 665         return self
.get_response() 
 667     def sinter(self
, *args
): 
 670         >>> res = r.delete('s1') 
 671         >>> res = r.delete('s2') 
 672         >>> res = r.delete('s3') 
 673         >>> r.sadd('s1', 'a') 
 675         >>> r.sadd('s2', 'a') 
 677         >>> r.sadd('s3', 'b') 
 681         ... except ResponseError, e: 
 683         wrong number of arguments 
 686         ... except ResponseError, e: 
 688         Operation against a key holding the wrong kind of value 
 689         >>> r.sinter('s1', 's2', 's3') 
 691         >>> r.sinter('s1', 's2') 
 696         self
._write
('SINTER %s\r\n' % ' '.join(args
)) 
 697         return set(self
.get_response()) 
 699     def sinterstore(self
, dest
, *args
): 
 702         >>> res = r.delete('s1') 
 703         >>> res = r.delete('s2') 
 704         >>> res = r.delete('s3') 
 705         >>> r.sadd('s1', 'a') 
 707         >>> r.sadd('s2', 'a') 
 709         >>> r.sadd('s3', 'b') 
 711         >>> r.sinterstore('s_s', 's1', 's2', 's3') 
 713         >>> r.sinterstore('s_s', 's1', 's2') 
 715         >>> r.smembers('s_s') 
 720         self
._write
('SINTERSTORE %s %s\r\n' % (dest
, ' '.join(args
))) 
 721         return self
.get_response() 
 723     def smembers(self
, name
): 
 734         ... except ResponseError, e: 
 736         Operation against a key holding the wrong kind of value 
 742         self
._write
('SMEMBERS %s\r\n' % name
) 
 743         return set(self
.get_response()) 
 745     def select(self
, db
): 
 760         self
._write
('SELECT %s\r\n' % db
) 
 761         return self
.get_response() 
 763     def move(self
, name
, db
): 
 789         self
._write
('MOVE %s %s\r\n' % (name
, db
)) 
 790         return self
.get_response() 
 792     def save(self
, background
=False): 
 798         ...     resp = r.save(background=True) 
 799         ... except ResponseError, e: 
 800         ...     assert str(e) == 'background save already in progress', str(e) 
 802         ...     assert resp == 'OK' 
 807             self
._write
('BGSAVE\r\n') 
 809             self
._write
('SAVE\r\n') 
 810         return self
.get_response() 
 816         >>> t = int(time.time()) 
 819         >>> r.lastsave() >= t 
 824         self
._write
('LASTSAVE\r\n') 
 825         return self
.get_response() 
 827     def flush(self
, all_dbs
=False): 
 832         >>> # r.flush(all_dbs=True) 
 836         self
._write
('%s\r\n' % ('FLUSHALL' if all_dbs 
else 'FLUSHDB')) 
 837         return self
.get_response() 
 843         >>> info and isinstance(info, dict) 
 845         >>> isinstance(info.get('connected_clients'), int) 
 850         self
._write
('INFO\r\n') 
 852         for l 
in self
.get_response().split('\r\n'): 
 855             k
, v 
= l
.split(':', 1) 
 856             info
[k
] = int(v
) if v
.isdigit() else v
 
 859     def get_response(self
): 
 860         data 
= self
._read
().strip() 
 863             raise ResponseError(data
[5:] if data
[:5] == '-ERR ' else data
[1:]) 
 869             except (TypeError, ValueError): 
 870                 raise InvalidResponse("Cannot convert multi-response header '%s' to integer" % data
) 
 873                 result
.append(self
._get
_value
()) 
 875         return self
._get
_value
(data
) 
 877     def _get_value(self
, data
=None): 
 878         data 
= data 
or self
._read
().strip() 
 882             c
, i 
= data
[0], (int(data
[1:]) if data
.find('.') == -1 else float(data
[1:])) 
 884             raise InvalidResponse("Cannot convert data '%s' to integer" % data
) 
 888             raise InvalidResponse("Unkown response prefix for '%s'" % data
) 
 896         return ''.join(buf
)[:-2] 
 898     def disconnect(self
): 
 899         if isinstance(self
._sock
, socket
.socket
): 
 911         >>> isinstance(r._sock, socket.socket) 
 916         if isinstance(self
._sock
, socket
.socket
): 
 919             sock 
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
) 
 920             sock
.connect((self
.host
, self
.port
)) 
 921         except socket
.error
, e
: 
 922             raise ConnectionError("Error %s connecting to %s:%s. %s." % (e
.args
[0], self
.host
, self
.port
, e
.args
[1])) 
 925             self
._fp 
= self
._sock
.makefile('r') 
 930 if __name__ 
== '__main__':