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