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