PageRenderTime 59ms CodeModel.GetById 12ms app.highlight 39ms RepoModel.GetById 1ms app.codeStats 0ms

/client-libraries/python/redis.py

http://redis.googlecode.com/
Python | 930 lines | 897 code | 15 blank | 18 comment | 13 complexity | 314fccd652d2b0d68615e677818dbb70 MD5 | raw file
  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 (Tue, 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    
 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            
927if __name__ == '__main__':
928    import doctest
929    doctest.testmod()
930