]> git.saurik.com Git - redis.git/blame - client-libraries/python/redis.py
Python lib updated
[redis.git] / client-libraries / python / redis.py
CommitLineData
f7acd603 1#!/usr/bin/env python
ed9b544e 2
3""" redis.py - A client for the Redis daemon.
4
f7acd603 5History:
6
7 - 20090603 fix missing errno import, add sunion and sunionstore commands,
8 generalize shebang (Jochen Kupperschmidt)
9
ed9b544e 10"""
11
12__author__ = "Ludovico Magnocavallo <ludo\x40qix\x2eit>"
13__copyright__ = "Copyright 2009, Ludovico Magnocavallo"
14__license__ = "MIT"
15__version__ = "0.5"
16__revision__ = "$LastChangedRevision: 175 $"[22:-2]
17__date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18:-2]
18
19
20# TODO: Redis._get_multi_response
21
22
23import socket
be424283 24import decimal
f7acd603 25import errno
ed9b544e 26
27
28BUFSIZE = 4096
29
30
31class RedisError(Exception): pass
32class ConnectionError(RedisError): pass
33class ResponseError(RedisError): pass
34class InvalidResponse(RedisError): pass
35class InvalidData(RedisError): pass
36
37
38class Redis(object):
39 """The main Redis client.
40 """
41
be424283 42 def __init__(self, host=None, port=None, timeout=None, db=None, nodelay=None, charset='utf8', errors='strict'):
ed9b544e 43 self.host = host or 'localhost'
44 self.port = port or 6379
45 if timeout:
46 socket.setdefaulttimeout(timeout)
be424283 47 self.nodelay = nodelay
48 self.charset = charset
49 self.errors = errors
ed9b544e 50 self._sock = None
51 self._fp = None
39c8c0f2 52 self.db = db
ed9b544e 53
be424283 54 def _encode(self, s):
55 if isinstance(s, str):
56 return s
57 if isinstance(s, unicode):
58 try:
59 return s.encode(self.charset, self.errors)
60 except UnicodeEncodeError, e:
61 raise InvalidData("Error encoding unicode value '%s': %s" % (value.encode(self.charset, 'replace'), e))
62 return str(s)
63
ed9b544e 64 def _write(self, s):
65 """
39c8c0f2 66 >>> r = Redis(db=9)
ed9b544e 67 >>> r.connect()
68 >>> r._sock.close()
69 >>> try:
70 ... r._write('pippo')
71 ... except ConnectionError, e:
72 ... print e
73 Error 9 while writing to socket. Bad file descriptor.
74 >>>
75 >>>
76 """
77 try:
78 self._sock.sendall(s)
79 except socket.error, e:
80 if e.args[0] == 32:
81 # broken pipe
82 self.disconnect()
83 raise ConnectionError("Error %s while writing to socket. %s." % tuple(e.args))
84
85 def _read(self):
86 try:
87 return self._fp.readline()
88 except socket.error, e:
89 if e.args and e.args[0] == errno.EAGAIN:
90 return
91 self.disconnect()
92 raise ConnectionError("Error %s while reading from socket. %s." % tuple(e.args))
93 if not data:
94 self.disconnect()
95 raise ConnectionError("Socket connection closed when reading.")
96 return data
97
98 def ping(self):
99 """
39c8c0f2 100 >>> r = Redis(db=9)
ed9b544e 101 >>> r.ping()
102 'PONG'
103 >>>
104 """
105 self.connect()
106 self._write('PING\r\n')
11cb1537 107 return self.get_response()
ed9b544e 108
be424283 109 def set(self, name, value, preserve=False, getset=False):
ed9b544e 110 """
39c8c0f2 111 >>> r = Redis(db=9)
ed9b544e 112 >>> r.set('a', 'pippo')
113 'OK'
be424283 114 >>> r.set('a', u'pippo \u3235')
115 'OK'
116 >>> r.get('a')
117 u'pippo \u3235'
ed9b544e 118 >>> r.set('b', 105.2)
119 'OK'
120 >>> r.set('b', 'xxx', preserve=True)
121 0
122 >>> r.get('b')
be424283 123 Decimal("105.2")
ed9b544e 124 >>>
125 """
126 self.connect()
127 # the following will raise an error for unicode values that can't be encoded to ascii
128 # we could probably add an 'encoding' arg to init, but then what do we do with get()?
129 # convert back to unicode? and what about ints, or pickled values?
be424283 130 if getset: command = 'GETSET'
131 elif preserve: command = 'SETNX'
132 else: command = 'SET'
133 value = self._encode(value)
134 self._write('%s %s %s\r\n%s\r\n' % (
135 command, name, len(value), value
ed9b544e 136 ))
11cb1537 137 return self.get_response()
ed9b544e 138
139 def get(self, name):
140 """
39c8c0f2
LM
141 >>> r = Redis(db=9)
142 >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n')
ed9b544e 143 ('OK', 'OK', 'OK', 'OK')
144 >>> r.get('a')
be424283 145 u'pippo'
ed9b544e 146 >>> r.get('b')
be424283 147 15
ed9b544e 148 >>> r.get('d')
be424283 149 u'\\r\\n'
ed9b544e 150 >>> r.get('b')
be424283 151 15
ed9b544e 152 >>> r.get('c')
be424283 153 u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
ed9b544e 154 >>> r.get('c')
be424283 155 u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
ed9b544e 156 >>> r.get('ajhsd')
157 >>>
158 """
159 self.connect()
160 self._write('GET %s\r\n' % name)
11cb1537
LM
161 return self.get_response()
162
be424283 163 def getset(self, name, value):
164 """
165 >>> r = Redis(db=9)
166 >>> r.set('a', 'pippo')
167 'OK'
168 >>> r.getset('a', 2)
169 u'pippo'
170 >>>
171 """
172 return self.set(name, value, getset=True)
173
11cb1537
LM
174 def mget(self, *args):
175 """
39c8c0f2 176 >>> r = Redis(db=9)
11cb1537
LM
177 >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n')
178 ('OK', 'OK', 'OK', 'OK')
179 >>> r.mget('a', 'b', 'c', 'd')
be424283 180 [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n']
11cb1537
LM
181 >>>
182 """
183 self.connect()
184 self._write('MGET %s\r\n' % ' '.join(args))
185 return self.get_response()
ed9b544e 186
187 def incr(self, name, amount=1):
188 """
39c8c0f2 189 >>> r = Redis(db=9)
ed9b544e 190 >>> r.delete('a')
191 1
192 >>> r.incr('a')
193 1
194 >>> r.incr('a')
195 2
196 >>> r.incr('a', 2)
197 4
198 >>>
199 """
200 self.connect()
201 if amount == 1:
202 self._write('INCR %s\r\n' % name)
203 else:
204 self._write('INCRBY %s %s\r\n' % (name, amount))
11cb1537 205 return self.get_response()
ed9b544e 206
207 def decr(self, name, amount=1):
208 """
39c8c0f2 209 >>> r = Redis(db=9)
ed9b544e 210 >>> if r.get('a'):
211 ... r.delete('a')
212 ... else:
213 ... print 1
214 1
215 >>> r.decr('a')
216 -1
217 >>> r.decr('a')
218 -2
219 >>> r.decr('a', 5)
220 -7
221 >>>
222 """
223 self.connect()
224 if amount == 1:
225 self._write('DECR %s\r\n' % name)
226 else:
227 self._write('DECRBY %s %s\r\n' % (name, amount))
11cb1537 228 return self.get_response()
ed9b544e 229
230 def exists(self, name):
231 """
39c8c0f2 232 >>> r = Redis(db=9)
ed9b544e 233 >>> r.exists('dsjhfksjdhfkdsjfh')
234 0
235 >>> r.set('a', 'a')
236 'OK'
237 >>> r.exists('a')
238 1
239 >>>
240 """
241 self.connect()
242 self._write('EXISTS %s\r\n' % name)
11cb1537 243 return self.get_response()
ed9b544e 244
245 def delete(self, name):
246 """
39c8c0f2 247 >>> r = Redis(db=9)
ed9b544e 248 >>> r.delete('dsjhfksjdhfkdsjfh')
249 0
250 >>> r.set('a', 'a')
251 'OK'
252 >>> r.delete('a')
253 1
254 >>> r.exists('a')
255 0
256 >>> r.delete('a')
257 0
258 >>>
259 """
260 self.connect()
261 self._write('DEL %s\r\n' % name)
11cb1537 262 return self.get_response()
ed9b544e 263
ab48d029 264 def get_type(self, name):
ed9b544e 265 """
ab48d029
LM
266 >>> r = Redis(db=9)
267 >>> r.set('a', 3)
268 'OK'
269 >>> r.get_type('a')
270 'string'
271 >>> r.get_type('zzz')
272 >>>
ed9b544e 273 """
274 self.connect()
275 self._write('TYPE %s\r\n' % name)
ab48d029
LM
276 res = self.get_response()
277 return None if res == 'none' else res
ed9b544e 278
279 def keys(self, pattern):
280 """
39c8c0f2 281 >>> r = Redis(db=9)
ed9b544e 282 >>> r.flush()
283 'OK'
284 >>> r.set('a', 'a')
285 'OK'
286 >>> r.keys('a*')
be424283 287 [u'a']
ed9b544e 288 >>> r.set('a2', 'a')
289 'OK'
290 >>> r.keys('a*')
be424283 291 [u'a', u'a2']
ed9b544e 292 >>> r.delete('a2')
293 1
294 >>> r.keys('sjdfhskjh*')
295 []
296 >>>
297 """
298 self.connect()
299 self._write('KEYS %s\r\n' % pattern)
11cb1537 300 return self.get_response().split()
ed9b544e 301
302 def randomkey(self):
303 """
39c8c0f2 304 >>> r = Redis(db=9)
ed9b544e 305 >>> r.set('a', 'a')
306 'OK'
307 >>> isinstance(r.randomkey(), str)
308 True
309 >>>
310 """
311 #raise NotImplementedError("Implemented but buggy, do not use.")
312 self.connect()
313 self._write('RANDOMKEY\r\n')
11cb1537 314 return self.get_response()
ed9b544e 315
316 def rename(self, src, dst, preserve=False):
317 """
39c8c0f2 318 >>> r = Redis(db=9)
ed9b544e 319 >>> try:
320 ... r.rename('a', 'a')
321 ... except ResponseError, e:
322 ... print e
11cb1537 323 source and destination objects are the same
ed9b544e 324 >>> r.rename('a', 'b')
325 'OK'
326 >>> try:
327 ... r.rename('a', 'b')
328 ... except ResponseError, e:
329 ... print e
330 no such key
331 >>> r.set('a', 1)
332 'OK'
333 >>> r.rename('b', 'a', preserve=True)
334 0
335 >>>
336 """
337 self.connect()
338 if preserve:
339 self._write('RENAMENX %s %s\r\n' % (src, dst))
11cb1537 340 return self.get_response()
ed9b544e 341 else:
342 self._write('RENAME %s %s\r\n' % (src, dst))
39c8c0f2 343 return self.get_response() #.strip()
ab48d029 344
be424283 345 def dbsize(self):
346 """
347 >>> r = Redis(db=9)
348 >>> type(r.dbsize())
349 <type 'int'>
350 >>>
351 """
352 self.connect()
353 self._write('DBSIZE\r\n')
354 return self.get_response()
355
356 def ttl(self, name):
357 """
358 >>> r = Redis(db=9)
359 >>> r.ttl('a')
360 -1
361 >>> r.expire('a', 10)
362 1
363 >>> r.ttl('a')
364 10
365 >>> r.expire('a', 0)
366 0
367 >>>
368 """
369 self.connect()
370 self._write('TTL %s\r\n' % name)
371 return self.get_response()
372
ab48d029
LM
373 def expire(self, name, time):
374 """
375 >>> r = Redis(db=9)
376 >>> r.set('a', 1)
377 'OK'
378 >>> r.expire('a', 1)
379 1
380 >>> r.expire('zzzzz', 1)
381 0
382 >>>
383 """
384 self.connect()
385 self._write('EXPIRE %s %s\r\n' % (name, time))
386 return self.get_response()
ed9b544e 387
388 def push(self, name, value, tail=False):
389 """
39c8c0f2 390 >>> r = Redis(db=9)
ed9b544e 391 >>> r.delete('l')
392 1
393 >>> r.push('l', 'a')
394 'OK'
395 >>> r.set('a', 'a')
396 'OK'
397 >>> try:
398 ... r.push('a', 'a')
399 ... except ResponseError, e:
400 ... print e
401 Operation against a key holding the wrong kind of value
402 >>>
403 """
404 self.connect()
be424283 405 value = self._encode(value)
406 self._write('%s %s %s\r\n%s\r\n' % (
407 'LPUSH' if tail else 'RPUSH', name, len(value), value
408 ))
11cb1537 409 return self.get_response()
ed9b544e 410
411 def llen(self, name):
412 """
39c8c0f2 413 >>> r = Redis(db=9)
ed9b544e 414 >>> r.delete('l')
415 1
416 >>> r.push('l', 'a')
417 'OK'
418 >>> r.llen('l')
419 1
420 >>> r.push('l', 'a')
421 'OK'
422 >>> r.llen('l')
423 2
424 >>>
425 """
426 self.connect()
427 self._write('LLEN %s\r\n' % name)
11cb1537 428 return self.get_response()
ed9b544e 429
430 def lrange(self, name, start, end):
431 """
39c8c0f2 432 >>> r = Redis(db=9)
ed9b544e 433 >>> r.delete('l')
434 1
435 >>> r.lrange('l', 0, 1)
436 []
437 >>> r.push('l', 'aaa')
438 'OK'
439 >>> r.lrange('l', 0, 1)
be424283 440 [u'aaa']
ed9b544e 441 >>> r.push('l', 'bbb')
442 'OK'
443 >>> r.lrange('l', 0, 0)
be424283 444 [u'aaa']
ed9b544e 445 >>> r.lrange('l', 0, 1)
be424283 446 [u'aaa', u'bbb']
ed9b544e 447 >>> r.lrange('l', -1, 0)
448 []
449 >>> r.lrange('l', -1, -1)
be424283 450 [u'bbb']
ed9b544e 451 >>>
452 """
453 self.connect()
454 self._write('LRANGE %s %s %s\r\n' % (name, start, end))
11cb1537 455 return self.get_response()
ed9b544e 456
457 def ltrim(self, name, start, end):
458 """
39c8c0f2 459 >>> r = Redis(db=9)
ed9b544e 460 >>> r.delete('l')
461 1
462 >>> try:
463 ... r.ltrim('l', 0, 1)
464 ... except ResponseError, e:
465 ... print e
466 no such key
467 >>> r.push('l', 'aaa')
468 'OK'
469 >>> r.push('l', 'bbb')
470 'OK'
471 >>> r.push('l', 'ccc')
472 'OK'
473 >>> r.ltrim('l', 0, 1)
474 'OK'
475 >>> r.llen('l')
476 2
477 >>> r.ltrim('l', 99, 95)
478 'OK'
479 >>> r.llen('l')
480 0
481 >>>
482 """
483 self.connect()
484 self._write('LTRIM %s %s %s\r\n' % (name, start, end))
11cb1537 485 return self.get_response()
ed9b544e 486
487 def lindex(self, name, index):
488 """
39c8c0f2 489 >>> r = Redis(db=9)
ed9b544e 490 >>> res = r.delete('l')
491 >>> r.lindex('l', 0)
492 >>> r.push('l', 'aaa')
493 'OK'
494 >>> r.lindex('l', 0)
be424283 495 u'aaa'
ed9b544e 496 >>> r.lindex('l', 2)
497 >>> r.push('l', 'ccc')
498 'OK'
499 >>> r.lindex('l', 1)
be424283 500 u'ccc'
ed9b544e 501 >>> r.lindex('l', -1)
be424283 502 u'ccc'
ed9b544e 503 >>>
504 """
505 self.connect()
506 self._write('LINDEX %s %s\r\n' % (name, index))
11cb1537 507 return self.get_response()
ed9b544e 508
509 def pop(self, name, tail=False):
510 """
39c8c0f2 511 >>> r = Redis(db=9)
ed9b544e 512 >>> r.delete('l')
513 1
514 >>> r.pop('l')
515 >>> r.push('l', 'aaa')
516 'OK'
517 >>> r.push('l', 'bbb')
518 'OK'
519 >>> r.pop('l')
be424283 520 u'aaa'
ed9b544e 521 >>> r.pop('l')
be424283 522 u'bbb'
ed9b544e 523 >>> r.pop('l')
524 >>> r.push('l', 'aaa')
525 'OK'
526 >>> r.push('l', 'bbb')
527 'OK'
528 >>> r.pop('l', tail=True)
be424283 529 u'bbb'
ed9b544e 530 >>> r.pop('l')
be424283 531 u'aaa'
ed9b544e 532 >>> r.pop('l')
533 >>>
534 """
535 self.connect()
536 self._write('%s %s\r\n' % ('RPOP' if tail else 'LPOP', name))
11cb1537 537 return self.get_response()
ed9b544e 538
539 def lset(self, name, index, value):
540 """
39c8c0f2 541 >>> r = Redis(db=9)
ed9b544e 542 >>> r.delete('l')
543 1
544 >>> try:
545 ... r.lset('l', 0, 'a')
546 ... except ResponseError, e:
547 ... print e
548 no such key
549 >>> r.push('l', 'aaa')
550 'OK'
551 >>> try:
552 ... r.lset('l', 1, 'a')
553 ... except ResponseError, e:
554 ... print e
555 index out of range
556 >>> r.lset('l', 0, 'bbb')
557 'OK'
558 >>> r.lrange('l', 0, 1)
be424283 559 [u'bbb']
ed9b544e 560 >>>
561 """
562 self.connect()
be424283 563 value = self._encode(value)
564 self._write('LSET %s %s %s\r\n%s\r\n' % (
565 name, index, len(value), value
566 ))
11cb1537 567 return self.get_response()
ed9b544e 568
569 def lrem(self, name, value, num=0):
570 """
39c8c0f2 571 >>> r = Redis(db=9)
ed9b544e 572 >>> r.delete('l')
573 1
574 >>> r.push('l', 'aaa')
575 'OK'
576 >>> r.push('l', 'bbb')
577 'OK'
578 >>> r.push('l', 'aaa')
579 'OK'
580 >>> r.lrem('l', 'aaa')
581 2
582 >>> r.lrange('l', 0, 10)
be424283 583 [u'bbb']
ed9b544e 584 >>> r.push('l', 'aaa')
585 'OK'
586 >>> r.push('l', 'aaa')
587 'OK'
588 >>> r.lrem('l', 'aaa', 1)
589 1
590 >>> r.lrem('l', 'aaa', 1)
591 1
592 >>> r.lrem('l', 'aaa', 1)
593 0
594 >>>
595 """
596 self.connect()
be424283 597 value = self._encode(value)
598 self._write('LREM %s %s %s\r\n%s\r\n' % (
599 name, num, len(value), value
600 ))
11cb1537 601 return self.get_response()
ed9b544e 602
603 def sort(self, name, by=None, get=None, start=None, num=None, desc=False, alpha=False):
604 """
39c8c0f2 605 >>> r = Redis(db=9)
ed9b544e 606 >>> r.delete('l')
607 1
608 >>> r.push('l', 'ccc')
609 'OK'
610 >>> r.push('l', 'aaa')
611 'OK'
612 >>> r.push('l', 'ddd')
613 'OK'
614 >>> r.push('l', 'bbb')
615 'OK'
616 >>> r.sort('l', alpha=True)
be424283 617 [u'aaa', u'bbb', u'ccc', u'ddd']
ed9b544e 618 >>> r.delete('l')
619 1
620 >>> for i in range(1, 5):
621 ... res = r.push('l', 1.0 / i)
622 >>> r.sort('l')
be424283 623 [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")]
ed9b544e 624 >>> r.sort('l', desc=True)
be424283 625 [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")]
ed9b544e 626 >>> r.sort('l', desc=True, start=2, num=1)
be424283 627 [Decimal("0.333333333333")]
ed9b544e 628 >>> r.set('weight_0.5', 10)
629 'OK'
630 >>> r.sort('l', desc=True, by='weight_*')
be424283 631 [Decimal("0.5"), Decimal("1.0"), Decimal("0.333333333333"), Decimal("0.25")]
ed9b544e 632 >>> for i in r.sort('l', desc=True):
633 ... res = r.set('test_%s' % i, 100 - float(i))
634 >>> r.sort('l', desc=True, get='test_*')
be424283 635 [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")]
ed9b544e 636 >>> r.sort('l', desc=True, by='weight_*', get='test_*')
be424283 637 [Decimal("99.5"), Decimal("99.0"), Decimal("99.6666666667"), Decimal("99.75")]
ed9b544e 638 >>> r.sort('l', desc=True, by='weight_*', get='missing_*')
639 [None, None, None, None]
640 >>>
641 """
642 stmt = ['SORT', name]
643 if by:
644 stmt.append("BY %s" % by)
645 if start and num:
646 stmt.append("LIMIT %s %s" % (start, num))
647 if get is None:
648 pass
649 elif isinstance(get, basestring):
650 stmt.append("GET %s" % get)
651 elif isinstance(get, list) or isinstance(get, tuple):
652 for g in get:
653 stmt.append("GET %s" % g)
654 else:
655 raise RedisError("Invalid parameter 'get' for Redis sort")
656 if desc:
657 stmt.append("DESC")
658 if alpha:
659 stmt.append("ALPHA")
660 self.connect()
661 self._write(' '.join(stmt + ["\r\n"]))
11cb1537 662 return self.get_response()
ed9b544e 663
664 def sadd(self, name, value):
665 """
39c8c0f2 666 >>> r = Redis(db=9)
ed9b544e 667 >>> res = r.delete('s')
668 >>> r.sadd('s', 'a')
669 1
670 >>> r.sadd('s', 'b')
671 1
672 >>>
673 """
674 self.connect()
be424283 675 value = self._encode(value)
676 self._write('SADD %s %s\r\n%s\r\n' % (
677 name, len(value), value
678 ))
11cb1537 679 return self.get_response()
ed9b544e 680
681 def srem(self, name, value):
682 """
39c8c0f2 683 >>> r = Redis(db=9)
ed9b544e 684 >>> r.delete('s')
685 1
686 >>> r.srem('s', 'aaa')
687 0
688 >>> r.sadd('s', 'b')
689 1
690 >>> r.srem('s', 'b')
691 1
692 >>> r.sismember('s', 'b')
693 0
694 >>>
695 """
696 self.connect()
be424283 697 value = self._encode(value)
698 self._write('SREM %s %s\r\n%s\r\n' % (
699 name, len(value), value
700 ))
11cb1537 701 return self.get_response()
ed9b544e 702
703 def sismember(self, name, value):
704 """
39c8c0f2 705 >>> r = Redis(db=9)
ed9b544e 706 >>> r.delete('s')
707 1
708 >>> r.sismember('s', 'b')
709 0
710 >>> r.sadd('s', 'a')
711 1
712 >>> r.sismember('s', 'b')
713 0
714 >>> r.sismember('s', 'a')
715 1
716 >>>
717 """
718 self.connect()
be424283 719 value = self._encode(value)
720 self._write('SISMEMBER %s %s\r\n%s\r\n' % (
721 name, len(value), value
722 ))
11cb1537 723 return self.get_response()
ed9b544e 724
725 def sinter(self, *args):
726 """
39c8c0f2 727 >>> r = Redis(db=9)
ed9b544e 728 >>> res = r.delete('s1')
729 >>> res = r.delete('s2')
730 >>> res = r.delete('s3')
731 >>> r.sadd('s1', 'a')
732 1
733 >>> r.sadd('s2', 'a')
734 1
735 >>> r.sadd('s3', 'b')
736 1
737 >>> try:
738 ... r.sinter()
739 ... except ResponseError, e:
740 ... print e
741 wrong number of arguments
742 >>> try:
743 ... r.sinter('l')
744 ... except ResponseError, e:
745 ... print e
746 Operation against a key holding the wrong kind of value
747 >>> r.sinter('s1', 's2', 's3')
748 set([])
749 >>> r.sinter('s1', 's2')
be424283 750 set([u'a'])
ed9b544e 751 >>>
752 """
753 self.connect()
754 self._write('SINTER %s\r\n' % ' '.join(args))
11cb1537 755 return set(self.get_response())
ed9b544e 756
757 def sinterstore(self, dest, *args):
758 """
39c8c0f2 759 >>> r = Redis(db=9)
ed9b544e 760 >>> res = r.delete('s1')
761 >>> res = r.delete('s2')
762 >>> res = r.delete('s3')
763 >>> r.sadd('s1', 'a')
764 1
765 >>> r.sadd('s2', 'a')
766 1
767 >>> r.sadd('s3', 'b')
768 1
769 >>> r.sinterstore('s_s', 's1', 's2', 's3')
be424283 770 0
ed9b544e 771 >>> r.sinterstore('s_s', 's1', 's2')
be424283 772 1
ed9b544e 773 >>> r.smembers('s_s')
be424283 774 set([u'a'])
ed9b544e 775 >>>
776 """
777 self.connect()
778 self._write('SINTERSTORE %s %s\r\n' % (dest, ' '.join(args)))
11cb1537 779 return self.get_response()
ed9b544e 780
781 def smembers(self, name):
782 """
39c8c0f2 783 >>> r = Redis(db=9)
ed9b544e 784 >>> r.delete('s')
785 1
786 >>> r.sadd('s', 'a')
787 1
788 >>> r.sadd('s', 'b')
789 1
790 >>> try:
791 ... r.smembers('l')
792 ... except ResponseError, e:
793 ... print e
794 Operation against a key holding the wrong kind of value
795 >>> r.smembers('s')
be424283 796 set([u'a', u'b'])
ed9b544e 797 >>>
798 """
799 self.connect()
800 self._write('SMEMBERS %s\r\n' % name)
11cb1537 801 return set(self.get_response())
ed9b544e 802
f7acd603 803 def sunion(self, *args):
804 """
805 >>> r = Redis(db=9)
806 >>> res = r.delete('s1')
807 >>> res = r.delete('s2')
808 >>> res = r.delete('s3')
809 >>> r.sadd('s1', 'a')
810 1
811 >>> r.sadd('s2', 'a')
812 1
813 >>> r.sadd('s3', 'b')
814 1
815 >>> r.sunion('s1', 's2', 's3')
816 set([u'a', u'b'])
817 >>> r.sadd('s2', 'c')
818 1
819 >>> r.sunion('s1', 's2', 's3')
820 set([u'a', u'c', u'b'])
821 >>>
822 """
823 self.connect()
824 self._write('SUNION %s\r\n' % ' '.join(args))
825 return set(self.get_response())
826
827 def sunionstore(self, dest, *args):
828 """
829 >>> r = Redis(db=9)
830 >>> res = r.delete('s1')
831 >>> res = r.delete('s2')
832 >>> res = r.delete('s3')
833 >>> r.sadd('s1', 'a')
834 1
835 >>> r.sadd('s2', 'a')
836 1
837 >>> r.sadd('s3', 'b')
838 1
839 >>> r.sunionstore('s4', 's1', 's2', 's3')
840 2
841 >>> r.smembers('s4')
842 set([u'a', u'b'])
843 >>>
844 """
845 self.connect()
846 self._write('SUNIONSTORE %s %s\r\n' % (dest, ' '.join(args)))
847 return self.get_response()
848
ed9b544e 849 def select(self, db):
850 """
39c8c0f2 851 >>> r = Redis(db=9)
ed9b544e 852 >>> r.delete('a')
853 1
491d908b 854 >>> r.select(10)
ed9b544e 855 'OK'
856 >>> r.set('a', 1)
857 'OK'
491d908b 858 >>> r.select(9)
ed9b544e 859 'OK'
860 >>> r.get('a')
861 >>>
862 """
863 self.connect()
864 self._write('SELECT %s\r\n' % db)
11cb1537 865 return self.get_response()
ed9b544e 866
867 def move(self, name, db):
868 """
39c8c0f2 869 >>> r = Redis(db=9)
ed9b544e 870 >>> r.set('a', 'a')
871 'OK'
39c8c0f2 872 >>> r.select(10)
ed9b544e 873 'OK'
874 >>> if r.get('a'):
875 ... r.delete('a')
876 ... else:
877 ... print 1
878 1
39c8c0f2 879 >>> r.select(9)
ed9b544e 880 'OK'
39c8c0f2 881 >>> r.move('a', 10)
ed9b544e 882 1
883 >>> r.get('a')
39c8c0f2 884 >>> r.select(10)
ed9b544e 885 'OK'
886 >>> r.get('a')
be424283 887 u'a'
39c8c0f2 888 >>> r.select(9)
ed9b544e 889 'OK'
890 >>>
891 """
892 self.connect()
893 self._write('MOVE %s %s\r\n' % (name, db))
11cb1537 894 return self.get_response()
ed9b544e 895
896 def save(self, background=False):
897 """
39c8c0f2 898 >>> r = Redis(db=9)
ed9b544e 899 >>> r.save()
900 'OK'
901 >>> try:
902 ... resp = r.save(background=True)
903 ... except ResponseError, e:
904 ... assert str(e) == 'background save already in progress', str(e)
905 ... else:
906 ... assert resp == 'OK'
907 >>>
908 """
909 self.connect()
910 if background:
911 self._write('BGSAVE\r\n')
912 else:
913 self._write('SAVE\r\n')
11cb1537 914 return self.get_response()
ed9b544e 915
916 def lastsave(self):
917 """
918 >>> import time
39c8c0f2 919 >>> r = Redis(db=9)
ed9b544e 920 >>> t = int(time.time())
921 >>> r.save()
922 'OK'
923 >>> r.lastsave() >= t
924 True
925 >>>
926 """
927 self.connect()
928 self._write('LASTSAVE\r\n')
11cb1537 929 return self.get_response()
ed9b544e 930
931 def flush(self, all_dbs=False):
932 """
39c8c0f2 933 >>> r = Redis(db=9)
ed9b544e 934 >>> r.flush()
935 'OK'
39c8c0f2 936 >>> # r.flush(all_dbs=True)
ed9b544e 937 >>>
938 """
939 self.connect()
940 self._write('%s\r\n' % ('FLUSHALL' if all_dbs else 'FLUSHDB'))
11cb1537
LM
941 return self.get_response()
942
943 def info(self):
944 """
39c8c0f2 945 >>> r = Redis(db=9)
11cb1537
LM
946 >>> info = r.info()
947 >>> info and isinstance(info, dict)
948 True
949 >>> isinstance(info.get('connected_clients'), int)
950 True
951 >>>
952 """
953 self.connect()
954 self._write('INFO\r\n')
955 info = dict()
956 for l in self.get_response().split('\r\n'):
957 if not l:
958 continue
959 k, v = l.split(':', 1)
960 info[k] = int(v) if v.isdigit() else v
961 return info
ed9b544e 962
be424283 963 def auth(self, passwd):
964 self.connect()
965 self._write('AUTH %s\r\n' % passwd)
966 return self.get_response()
967
11cb1537 968 def get_response(self):
ed9b544e 969 data = self._read().strip()
b062edf3
LM
970 if not data:
971 self.disconnect()
972 raise ConnectionError("Socket closed on remote end")
11cb1537
LM
973 c = data[0]
974 if c == '-':
975 raise ResponseError(data[5:] if data[:5] == '-ERR ' else data[1:])
976 if c == '+':
977 return data[1:]
978 if c == '*':
979 try:
980 num = int(data[1:])
981 except (TypeError, ValueError):
982 raise InvalidResponse("Cannot convert multi-response header '%s' to integer" % data)
983 result = list()
984 for i in range(num):
985 result.append(self._get_value())
986 return result
987 return self._get_value(data)
988
989 def _get_value(self, data=None):
990 data = data or self._read().strip()
991 if data == '$-1':
992 return None
ed9b544e 993 try:
11cb1537
LM
994 c, i = data[0], (int(data[1:]) if data.find('.') == -1 else float(data[1:]))
995 except ValueError:
996 raise InvalidResponse("Cannot convert data '%s' to integer" % data)
997 if c == ':':
998 return i
999 if c != '$':
1000 raise InvalidResponse("Unkown response prefix for '%s'" % data)
ed9b544e 1001 buf = []
39c8c0f2 1002 while True:
ed9b544e 1003 data = self._read()
11cb1537 1004 i -= len(data)
ed9b544e 1005 buf.append(data)
39c8c0f2
LM
1006 if i < 0:
1007 break
be424283 1008 data = ''.join(buf)[:-2]
1009 try:
1010 return int(data) if data.find('.') == -1 else decimal.Decimal(data)
1011 except (ValueError, decimal.InvalidOperation):
1012 return data.decode(self.charset)
ed9b544e 1013
ed9b544e 1014 def disconnect(self):
1015 if isinstance(self._sock, socket.socket):
1016 try:
1017 self._sock.close()
1018 except socket.error:
1019 pass
1020 self._sock = None
1021 self._fp = None
1022
1023 def connect(self):
1024 """
39c8c0f2 1025 >>> r = Redis(db=9)
ed9b544e 1026 >>> r.connect()
1027 >>> isinstance(r._sock, socket.socket)
1028 True
39c8c0f2 1029 >>> r.disconnect()
ed9b544e 1030 >>>
1031 """
1032 if isinstance(self._sock, socket.socket):
1033 return
1034 try:
1035 sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
1036 sock.connect((self.host, self.port))
1037 except socket.error, e:
1038 raise ConnectionError("Error %s connecting to %s:%s. %s." % (e.args[0], self.host, self.port, e.args[1]))
1039 else:
1040 self._sock = sock
1041 self._fp = self._sock.makefile('r')
39c8c0f2
LM
1042 if self.db:
1043 self.select(self.db)
be424283 1044 if self.nodelay is not None:
1045 self._sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, self.nodelay)
39c8c0f2 1046
ed9b544e 1047
1048if __name__ == '__main__':
1049 import doctest
1050 doctest.testmod()
491d908b 1051