]> git.saurik.com Git - redis.git/blobdiff - client-libraries/python/redis.py
Python lib updated
[redis.git] / client-libraries / python / redis.py
index 6187cf9d42de4ba0651ffcdb9157ff0e11fbeb5b..9618901ea7227a00682bc0f07fa070502cabbe01 100644 (file)
@@ -1,7 +1,12 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 
 """ redis.py - A client for the Redis daemon.
 
+History:
+
+        - 20090603 fix missing errno import, add sunion and sunionstore commands,
+          generalize shebang (Jochen Kupperschmidt)
+
 """
 
 __author__ = "Ludovico Magnocavallo <ludo\x40qix\x2eit>"
@@ -16,6 +21,8 @@ __date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18
 
 
 import socket
+import decimal
+import errno
 
 
 BUFSIZE = 4096
@@ -32,17 +39,31 @@ class Redis(object):
     """The main Redis client.
     """
     
-    def __init__(self, host=None, port=None, timeout=None):
+    def __init__(self, host=None, port=None, timeout=None, db=None, nodelay=None, charset='utf8', errors='strict'):
         self.host = host or 'localhost'
         self.port = port or 6379
         if timeout:
             socket.setdefaulttimeout(timeout)
+        self.nodelay = nodelay
+        self.charset = charset
+        self.errors = errors
         self._sock = None
         self._fp = None
+        self.db = db
         
+    def _encode(self, s):
+        if isinstance(s, str):
+            return s
+        if isinstance(s, unicode):
+            try:
+                return s.encode(self.charset, self.errors)
+            except UnicodeEncodeError, e:
+                raise InvalidData("Error encoding unicode value '%s': %s" % (value.encode(self.charset, 'replace'), e))
+        return str(s)
+    
     def _write(self, s):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.connect()
         >>> r._sock.close()
         >>> try:
@@ -76,7 +97,7 @@ class Redis(object):
     
     def ping(self):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.ping()
         'PONG'
         >>> 
@@ -85,54 +106,53 @@ class Redis(object):
         self._write('PING\r\n')
         return self.get_response()
     
-    def set(self, name, value, preserve=False):
+    def set(self, name, value, preserve=False, getset=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.set('a', 'pippo')
         'OK'
-        >>> try:
-        ...     r.set('a', u'pippo \u3235')
-        ... except InvalidData, e:
-        ...     print e
-        Error encoding unicode value for key 'a': 'ascii' codec can't encode character u'\u3235' in position 15: ordinal not in range(128).
+        >>> r.set('a', u'pippo \u3235')
+        'OK'
+        >>> r.get('a')
+        u'pippo \u3235'
         >>> r.set('b', 105.2)
         'OK'
         >>> r.set('b', 'xxx', preserve=True)
         0
         >>> r.get('b')
-        '105.2'
+        Decimal("105.2")
         >>> 
         """
         self.connect()
         # the following will raise an error for unicode values that can't be encoded to ascii
         # we could probably add an 'encoding' arg to init, but then what do we do with get()?
         # convert back to unicode? and what about ints, or pickled values?
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('%s %s %s\r\n%s\r\n' % (
-                'SETNX' if preserve else 'SET', name, len(value), value
+        if getset: command = 'GETSET'
+        elif preserve: command = 'SETNX'
+        else: command = 'SET'
+        value = self._encode(value)
+        self._write('%s %s %s\r\n%s\r\n' % (
+                command, name, len(value), value
             ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for key '%s': %s." % (name, e))
         return self.get_response()
     
     def get(self, name):
         """
-        >>> r = Redis()
-        >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n')
+        >>> r = Redis(db=9)
+        >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', ' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '), r.set('d', '\\r\\n')
         ('OK', 'OK', 'OK', 'OK')
         >>> r.get('a')
-        'pippo'
+        u'pippo'
         >>> r.get('b')
-        '15'
+        15
         >>> r.get('d')
-        '\\r\\n'
+        u'\\r\\n'
         >>> r.get('b')
-        '15'
+        15
         >>> r.get('c')
-        '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'
+        u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
         >>> r.get('c')
-        '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'
+        u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
         >>> r.get('ajhsd')
         >>> 
         """
@@ -140,13 +160,24 @@ class Redis(object):
         self._write('GET %s\r\n' % name)
         return self.get_response()
     
+    def getset(self, name, value):
+        """
+        >>> r = Redis(db=9)
+        >>> r.set('a', 'pippo')
+        'OK'
+        >>> r.getset('a', 2)
+        u'pippo'
+        >>> 
+        """
+        return self.set(name, value, getset=True)
+        
     def mget(self, *args):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.set('a', 'pippo'), r.set('b', 15), r.set('c', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n'), r.set('d', '\\r\\n')
         ('OK', 'OK', 'OK', 'OK')
         >>> r.mget('a', 'b', 'c', 'd')
-        ['pippo', '15', '\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', '\\r\\n']
+        [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n']
         >>> 
         """
         self.connect()
@@ -155,7 +186,7 @@ class Redis(object):
     
     def incr(self, name, amount=1):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('a')
         1
         >>> r.incr('a')
@@ -175,7 +206,7 @@ class Redis(object):
 
     def decr(self, name, amount=1):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> if r.get('a'):
         ...     r.delete('a')
         ... else:
@@ -198,7 +229,7 @@ class Redis(object):
     
     def exists(self, name):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.exists('dsjhfksjdhfkdsjfh')
         0
         >>> r.set('a', 'a')
@@ -213,7 +244,7 @@ class Redis(object):
 
     def delete(self, name):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('dsjhfksjdhfkdsjfh')
         0
         >>> r.set('a', 'a')
@@ -230,27 +261,34 @@ class Redis(object):
         self._write('DEL %s\r\n' % name)
         return self.get_response()
 
-    def key_type(self, name):
+    def get_type(self, name):
         """
-        Not yet implemented.
+        >>> r = Redis(db=9)
+        >>> r.set('a', 3)
+        'OK'
+        >>> r.get_type('a')
+        'string'
+        >>> r.get_type('zzz')
+        >>> 
         """
         self.connect()
         self._write('TYPE %s\r\n' % name)
-        return self.get_response()
+        res = self.get_response()
+        return None if res == 'none' else res
     
     def keys(self, pattern):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.flush()
         'OK'
         >>> r.set('a', 'a')
         'OK'
         >>> r.keys('a*')
-        ['a']
+        [u'a']
         >>> r.set('a2', 'a')
         'OK'
         >>> r.keys('a*')
-        ['a', 'a2']
+        [u'a', u'a2']
         >>> r.delete('a2')
         1
         >>> r.keys('sjdfhskjh*')
@@ -263,7 +301,7 @@ class Redis(object):
     
     def randomkey(self):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.set('a', 'a')
         'OK'
         >>> isinstance(r.randomkey(), str)
@@ -277,7 +315,7 @@ class Redis(object):
     
     def rename(self, src, dst, preserve=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> try:
         ...     r.rename('a', 'a')
         ... except ResponseError, e:
@@ -302,11 +340,54 @@ class Redis(object):
             return self.get_response()
         else:
             self._write('RENAME %s %s\r\n' % (src, dst))
-            return self.get_response().strip()
+            return self.get_response() #.strip()
+        
+    def dbsize(self):
+        """
+        >>> r = Redis(db=9)
+        >>> type(r.dbsize())
+        <type 'int'>
+        >>> 
+        """
+        self.connect()
+        self._write('DBSIZE\r\n')
+        return self.get_response()
+    
+    def ttl(self, name):
+        """
+        >>> r = Redis(db=9)
+        >>> r.ttl('a')
+        -1
+        >>> r.expire('a', 10)
+        1
+        >>> r.ttl('a')
+        10
+        >>> r.expire('a', 0)
+        0
+        >>> 
+        """
+        self.connect()
+        self._write('TTL %s\r\n' % name)
+        return self.get_response()
+    
+    def expire(self, name, time):
+        """
+        >>> r = Redis(db=9)
+        >>> r.set('a', 1)
+        'OK'
+        >>> r.expire('a', 1)
+        1
+        >>> r.expire('zzzzz', 1)
+        0
+        >>> 
+        """
+        self.connect()
+        self._write('EXPIRE %s %s\r\n' % (name, time))
+        return self.get_response()
     
     def push(self, name, value, tail=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.push('l', 'a')
@@ -321,19 +402,15 @@ class Redis(object):
         >>> 
         """
         self.connect()
-        # same considerations on unicode as in set() apply here
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('%s %s %s\r\n%s\r\n' % (
-                'LPUSH' if tail else 'RPUSH', name, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element in list '%s': %s." % (name, e))
+        value = self._encode(value)
+        self._write('%s %s %s\r\n%s\r\n' % (
+            'LPUSH' if tail else 'RPUSH', name, len(value), value
+        ))
         return self.get_response()
     
     def llen(self, name):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.push('l', 'a')
@@ -352,7 +429,7 @@ class Redis(object):
 
     def lrange(self, name, start, end):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.lrange('l', 0, 1)
@@ -360,17 +437,17 @@ class Redis(object):
         >>> r.push('l', 'aaa')
         'OK'
         >>> r.lrange('l', 0, 1)
-        ['aaa']
+        [u'aaa']
         >>> r.push('l', 'bbb')
         'OK'
         >>> r.lrange('l', 0, 0)
-        ['aaa']
+        [u'aaa']
         >>> r.lrange('l', 0, 1)
-        ['aaa', 'bbb']
+        [u'aaa', u'bbb']
         >>> r.lrange('l', -1, 0)
         []
         >>> r.lrange('l', -1, -1)
-        ['bbb']
+        [u'bbb']
         >>> 
         """
         self.connect()
@@ -379,7 +456,7 @@ class Redis(object):
         
     def ltrim(self, name, start, end):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> try:
@@ -409,20 +486,20 @@ class Redis(object):
     
     def lindex(self, name, index):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> res = r.delete('l')
         >>> r.lindex('l', 0)
         >>> r.push('l', 'aaa')
         'OK'
         >>> r.lindex('l', 0)
-        'aaa'
+        u'aaa'
         >>> r.lindex('l', 2)
         >>> r.push('l', 'ccc')
         'OK'
         >>> r.lindex('l', 1)
-        'ccc'
+        u'ccc'
         >>> r.lindex('l', -1)
-        'ccc'
+        u'ccc'
         >>> 
         """
         self.connect()
@@ -431,7 +508,7 @@ class Redis(object):
         
     def pop(self, name, tail=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.pop('l')
@@ -440,18 +517,18 @@ class Redis(object):
         >>> r.push('l', 'bbb')
         'OK'
         >>> r.pop('l')
-        'aaa'
+        u'aaa'
         >>> r.pop('l')
-        'bbb'
+        u'bbb'
         >>> r.pop('l')
         >>> r.push('l', 'aaa')
         'OK'
         >>> r.push('l', 'bbb')
         'OK'
         >>> r.pop('l', tail=True)
-        'bbb'
+        u'bbb'
         >>> r.pop('l')
-        'aaa'
+        u'aaa'
         >>> r.pop('l')
         >>> 
         """
@@ -461,7 +538,7 @@ class Redis(object):
     
     def lset(self, name, index, value):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> try:
@@ -479,22 +556,19 @@ class Redis(object):
         >>> r.lset('l', 0, 'bbb')
         'OK'
         >>> r.lrange('l', 0, 1)
-        ['bbb']
+        [u'bbb']
         >>> 
         """
         self.connect()
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('LSET %s %s %s\r\n%s\r\n' % (
-                name, index, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index, name, e))
+        value = self._encode(value)
+        self._write('LSET %s %s %s\r\n%s\r\n' % (
+            name, index, len(value), value
+        ))
         return self.get_response()
     
     def lrem(self, name, value, num=0):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.push('l', 'aaa')
@@ -506,7 +580,7 @@ class Redis(object):
         >>> r.lrem('l', 'aaa')
         2
         >>> r.lrange('l', 0, 10)
-        ['bbb']
+        [u'bbb']
         >>> r.push('l', 'aaa')
         'OK'
         >>> r.push('l', 'aaa')
@@ -520,18 +594,15 @@ class Redis(object):
         >>> 
         """
         self.connect()
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('LREM %s %s %s\r\n%s\r\n' % (
-                name, num, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element %s in list '%s': %s." % (index, name, e))
+        value = self._encode(value)
+        self._write('LREM %s %s %s\r\n%s\r\n' % (
+            name, num, len(value), value
+        ))
         return self.get_response()
     
     def sort(self, name, by=None, get=None, start=None, num=None, desc=False, alpha=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('l')
         1
         >>> r.push('l', 'ccc')
@@ -543,27 +614,27 @@ class Redis(object):
         >>> r.push('l', 'bbb')
         'OK'
         >>> r.sort('l', alpha=True)
-        ['aaa', 'bbb', 'ccc', 'ddd']
+        [u'aaa', u'bbb', u'ccc', u'ddd']
         >>> r.delete('l')
         1
         >>> for i in range(1, 5):
         ...     res = r.push('l', 1.0 / i)
         >>> r.sort('l')
-        ['0.25', '0.333333333333', '0.5', '1.0']
+        [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")]
         >>> r.sort('l', desc=True)
-        ['1.0', '0.5', '0.333333333333', '0.25']
+        [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")]
         >>> r.sort('l', desc=True, start=2, num=1)
-        ['0.333333333333']
+        [Decimal("0.333333333333")]
         >>> r.set('weight_0.5', 10)
         'OK'
         >>> r.sort('l', desc=True, by='weight_*')
-        ['0.5', '1.0', '0.333333333333', '0.25']
+        [Decimal("0.5"), Decimal("1.0"), Decimal("0.333333333333"), Decimal("0.25")]
         >>> for i in r.sort('l', desc=True):
         ...     res = r.set('test_%s' % i, 100 - float(i))
         >>> r.sort('l', desc=True, get='test_*')
-        ['99.0', '99.5', '99.6666666667', '99.75']
+        [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")]
         >>> r.sort('l', desc=True, by='weight_*', get='test_*')
-        ['99.5', '99.0', '99.6666666667', '99.75']
+        [Decimal("99.5"), Decimal("99.0"), Decimal("99.6666666667"), Decimal("99.75")]
         >>> r.sort('l', desc=True, by='weight_*', get='missing_*')
         [None, None, None, None]
         >>> 
@@ -592,7 +663,7 @@ class Redis(object):
     
     def sadd(self, name, value):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> res = r.delete('s')
         >>> r.sadd('s', 'a')
         1
@@ -601,19 +672,15 @@ class Redis(object):
         >>> 
         """
         self.connect()
-        # same considerations on unicode as in set() apply here
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('SADD %s %s\r\n%s\r\n' % (
-                name, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e))
+        value = self._encode(value)
+        self._write('SADD %s %s\r\n%s\r\n' % (
+            name, len(value), value
+        ))
         return self.get_response()
         
     def srem(self, name, value):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('s')
         1
         >>> r.srem('s', 'aaa')
@@ -627,19 +694,15 @@ class Redis(object):
         >>> 
         """
         self.connect()
-        # same considerations on unicode as in set() apply here
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('SREM %s %s\r\n%s\r\n' % (
-                name, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e))
+        value = self._encode(value)
+        self._write('SREM %s %s\r\n%s\r\n' % (
+            name, len(value), value
+        ))
         return self.get_response()
     
     def sismember(self, name, value):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('s')
         1
         >>> r.sismember('s', 'b')
@@ -653,19 +716,15 @@ class Redis(object):
         >>>
         """
         self.connect()
-        # same considerations on unicode as in set() apply here
-        try:
-            value = value if isinstance(value, basestring) else str(value)
-            self._write('SISMEMBER %s %s\r\n%s\r\n' % (
-                name, len(value), value
-            ))
-        except UnicodeEncodeError, e:
-            raise InvalidData("Error encoding unicode value for element in set '%s': %s." % (name, e))
+        value = self._encode(value)
+        self._write('SISMEMBER %s %s\r\n%s\r\n' % (
+            name, len(value), value
+        ))
         return self.get_response()
     
     def sinter(self, *args):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> res = r.delete('s1')
         >>> res = r.delete('s2')
         >>> res = r.delete('s3')
@@ -688,7 +747,7 @@ class Redis(object):
         >>> r.sinter('s1', 's2', 's3')
         set([])
         >>> r.sinter('s1', 's2')
-        set(['a'])
+        set([u'a'])
         >>> 
         """
         self.connect()
@@ -697,7 +756,7 @@ class Redis(object):
     
     def sinterstore(self, dest, *args):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> res = r.delete('s1')
         >>> res = r.delete('s2')
         >>> res = r.delete('s3')
@@ -708,11 +767,11 @@ class Redis(object):
         >>> r.sadd('s3', 'b')
         1
         >>> r.sinterstore('s_s', 's1', 's2', 's3')
-        'OK'
+        0
         >>> r.sinterstore('s_s', 's1', 's2')
-        'OK'
+        1
         >>> r.smembers('s_s')
-        set(['a'])
+        set([u'a'])
         >>> 
         """
         self.connect()
@@ -721,7 +780,7 @@ class Redis(object):
 
     def smembers(self, name):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('s')
         1
         >>> r.sadd('s', 'a')
@@ -734,23 +793,69 @@ class Redis(object):
         ...     print e
         Operation against a key holding the wrong kind of value
         >>> r.smembers('s')
-        set(['a', 'b'])
+        set([u'a', u'b'])
         >>> 
         """
         self.connect()
         self._write('SMEMBERS %s\r\n' % name)
         return set(self.get_response())
 
+    def sunion(self, *args):
+        """
+        >>> r = Redis(db=9)
+        >>> res = r.delete('s1')
+        >>> res = r.delete('s2')
+        >>> res = r.delete('s3')
+        >>> r.sadd('s1', 'a')
+        1
+        >>> r.sadd('s2', 'a')
+        1
+        >>> r.sadd('s3', 'b')
+        1
+        >>> r.sunion('s1', 's2', 's3')
+        set([u'a', u'b'])
+        >>> r.sadd('s2', 'c')
+        1
+        >>> r.sunion('s1', 's2', 's3')
+        set([u'a', u'c', u'b'])
+        >>> 
+        """
+        self.connect()
+        self._write('SUNION %s\r\n' % ' '.join(args))
+        return set(self.get_response())
+
+    def sunionstore(self, dest, *args):
+        """
+        >>> r = Redis(db=9)
+        >>> res = r.delete('s1')
+        >>> res = r.delete('s2')
+        >>> res = r.delete('s3')
+        >>> r.sadd('s1', 'a')
+        1
+        >>> r.sadd('s2', 'a')
+        1
+        >>> r.sadd('s3', 'b')
+        1
+        >>> r.sunionstore('s4', 's1', 's2', 's3')
+        2
+        >>> r.smembers('s4')
+        set([u'a', u'b'])
+        >>> 
+        """
+        self.connect()
+        self._write('SUNIONSTORE %s %s\r\n' % (dest, ' '.join(args)))
+        return self.get_response()
+
     def select(self, db):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.delete('a')
         1
-        >>> r.select(1)
+        >>> r.select(10)
         'OK'
         >>> r.set('a', 1)
         'OK'
-        >>> r.select(0)
+        >>> r.select(9)
         'OK'
         >>> r.get('a')
         >>> 
@@ -761,28 +866,26 @@ class Redis(object):
     
     def move(self, name, db):
         """
-        >>> r = Redis()
-        >>> r.select(0)
-        'OK'
+        >>> r = Redis(db=9)
         >>> r.set('a', 'a')
         'OK'
-        >>> r.select(1)
+        >>> r.select(10)
         'OK'
         >>> if r.get('a'):
         ...     r.delete('a')
         ... else:
         ...     print 1
         1
-        >>> r.select(0)
+        >>> r.select(9)
         'OK'
-        >>> r.move('a', 1)
+        >>> r.move('a', 10)
         1
         >>> r.get('a')
-        >>> r.select(1)
+        >>> r.select(10)
         'OK'
         >>> r.get('a')
-        'a'
-        >>> r.select(0)
+        u'a'
+        >>> r.select(9)
         'OK'
         >>> 
         """
@@ -792,7 +895,7 @@ class Redis(object):
     
     def save(self, background=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.save()
         'OK'
         >>> try:
@@ -813,7 +916,7 @@ class Redis(object):
     def lastsave(self):
         """
         >>> import time
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> t = int(time.time())
         >>> r.save()
         'OK'
@@ -827,11 +930,10 @@ class Redis(object):
     
     def flush(self, all_dbs=False):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.flush()
         'OK'
-        >>> r.flush(all_dbs=True)
-        'OK'
+        >>> # r.flush(all_dbs=True)
         >>> 
         """
         self.connect()
@@ -840,7 +942,7 @@ class Redis(object):
     
     def info(self):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> info = r.info()
         >>> info and isinstance(info, dict)
         True
@@ -858,8 +960,16 @@ class Redis(object):
             info[k] = int(v) if v.isdigit() else v
         return info
     
+    def auth(self, passwd):
+        self.connect()
+        self._write('AUTH %s\r\n' % passwd)
+        return self.get_response()
+    
     def get_response(self):
         data = self._read().strip()
+        if not data:
+            self.disconnect()
+            raise ConnectionError("Socket closed on remote end")
         c = data[0]
         if c == '-':
             raise ResponseError(data[5:] if data[:5] == '-ERR ' else data[1:])
@@ -889,17 +999,17 @@ class Redis(object):
         if c != '$':
             raise InvalidResponse("Unkown response prefix for '%s'" % data)
         buf = []
-        while i > 0:
+        while True:
             data = self._read()
             i -= len(data)
-            if len(data) > i:
-                # we got the ending crlf
-                data = data.rstrip()
             buf.append(data)
-        if i == 0:
-            # the data has a trailing crlf embedded, let's restore it
-            buf.append(self._read())
-        return ''.join(buf)
+            if i < 0:
+                break
+        data = ''.join(buf)[:-2]
+        try:
+            return int(data) if data.find('.') == -1 else decimal.Decimal(data)
+        except (ValueError, decimal.InvalidOperation):
+            return data.decode(self.charset)
     
     def disconnect(self):
         if isinstance(self._sock, socket.socket):
@@ -912,10 +1022,11 @@ class Redis(object):
             
     def connect(self):
         """
-        >>> r = Redis()
+        >>> r = Redis(db=9)
         >>> r.connect()
         >>> isinstance(r._sock, socket.socket)
         True
+        >>> r.disconnect()
         >>> 
         """
         if isinstance(self._sock, socket.socket):
@@ -928,9 +1039,13 @@ class Redis(object):
         else:
             self._sock = sock
             self._fp = self._sock.makefile('r')
-        
+            if self.db:
+                self.select(self.db)
+            if self.nodelay is not None:
+                self._sock.setsockopt(socket.SOL_TCP, socket.TCP_NODELAY, self.nodelay)
+                
             
 if __name__ == '__main__':
     import doctest
     doctest.testmod()
-    
\ No newline at end of file
+