]> git.saurik.com Git - redis.git/blobdiff - client-libraries/python/redis.py
client libs removed from Redis git
[redis.git] / client-libraries / python / redis.py
diff --git a/client-libraries/python/redis.py b/client-libraries/python/redis.py
deleted file mode 100644 (file)
index 9618901..0000000
+++ /dev/null
@@ -1,1051 +0,0 @@
-#!/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>"
-__copyright__ = "Copyright 2009, Ludovico Magnocavallo"
-__license__ = "MIT"
-__version__ = "0.5"
-__revision__ = "$LastChangedRevision: 175 $"[22:-2]
-__date__ = "$LastChangedDate: 2009-03-17 16:15:55 +0100 (Mar, 17 Mar 2009) $"[18:-2]
-
-
-# TODO: Redis._get_multi_response
-
-
-import socket
-import decimal
-import errno
-
-
-BUFSIZE = 4096
-
-
-class RedisError(Exception): pass
-class ConnectionError(RedisError): pass
-class ResponseError(RedisError): pass
-class InvalidResponse(RedisError): pass
-class InvalidData(RedisError): pass
-
-
-class Redis(object):
-    """The main Redis client.
-    """
-    
-    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(db=9)
-        >>> r.connect()
-        >>> r._sock.close()
-        >>> try:
-        ...     r._write('pippo')
-        ... except ConnectionError, e:
-        ...     print e
-        Error 9 while writing to socket. Bad file descriptor.
-        >>>
-        >>> 
-        """
-        try:
-            self._sock.sendall(s)
-        except socket.error, e:
-            if e.args[0] == 32:
-                # broken pipe
-                self.disconnect()
-            raise ConnectionError("Error %s while writing to socket. %s." % tuple(e.args))
-            
-    def _read(self):
-        try:
-            return self._fp.readline()
-        except socket.error, e:
-            if e.args and e.args[0] == errno.EAGAIN:
-                return
-            self.disconnect()
-            raise ConnectionError("Error %s while reading from socket. %s." % tuple(e.args))
-        if not data:
-            self.disconnect()
-            raise ConnectionError("Socket connection closed when reading.")
-        return data
-    
-    def ping(self):
-        """
-        >>> r = Redis(db=9)
-        >>> r.ping()
-        'PONG'
-        >>> 
-        """
-        self.connect()
-        self._write('PING\r\n')
-        return self.get_response()
-    
-    def set(self, name, value, preserve=False, getset=False):
-        """
-        >>> r = Redis(db=9)
-        >>> r.set('a', 'pippo')
-        'OK'
-        >>> 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')
-        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?
-        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
-            ))
-        return self.get_response()
-    
-    def get(self, name):
-        """
-        >>> 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')
-        u'pippo'
-        >>> r.get('b')
-        15
-        >>> r.get('d')
-        u'\\r\\n'
-        >>> r.get('b')
-        15
-        >>> r.get('c')
-        u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
-        >>> r.get('c')
-        u' \\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n '
-        >>> r.get('ajhsd')
-        >>> 
-        """
-        self.connect()
-        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(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')
-        [u'pippo', 15, u'\\r\\naaa\\nbbb\\r\\ncccc\\nddd\\r\\n', u'\\r\\n']
-        >>> 
-        """
-        self.connect()
-        self._write('MGET %s\r\n' % ' '.join(args))
-        return self.get_response()
-    
-    def incr(self, name, amount=1):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('a')
-        1
-        >>> r.incr('a')
-        1
-        >>> r.incr('a')
-        2
-        >>> r.incr('a', 2)
-        4
-        >>>
-        """
-        self.connect()
-        if amount == 1:
-            self._write('INCR %s\r\n' % name)
-        else:
-            self._write('INCRBY %s %s\r\n' % (name, amount))
-        return self.get_response()
-
-    def decr(self, name, amount=1):
-        """
-        >>> r = Redis(db=9)
-        >>> if r.get('a'):
-        ...     r.delete('a')
-        ... else:
-        ...     print 1
-        1
-        >>> r.decr('a')
-        -1
-        >>> r.decr('a')
-        -2
-        >>> r.decr('a', 5)
-        -7
-        >>> 
-        """
-        self.connect()
-        if amount == 1:
-            self._write('DECR %s\r\n' % name)
-        else:
-            self._write('DECRBY %s %s\r\n' % (name, amount))
-        return self.get_response()
-    
-    def exists(self, name):
-        """
-        >>> r = Redis(db=9)
-        >>> r.exists('dsjhfksjdhfkdsjfh')
-        0
-        >>> r.set('a', 'a')
-        'OK'
-        >>> r.exists('a')
-        1
-        >>>
-        """
-        self.connect()
-        self._write('EXISTS %s\r\n' % name)
-        return self.get_response()
-
-    def delete(self, name):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('dsjhfksjdhfkdsjfh')
-        0
-        >>> r.set('a', 'a')
-        'OK'
-        >>> r.delete('a')
-        1
-        >>> r.exists('a')
-        0
-        >>> r.delete('a')
-        0
-        >>> 
-        """
-        self.connect()
-        self._write('DEL %s\r\n' % name)
-        return self.get_response()
-
-    def get_type(self, name):
-        """
-        >>> 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)
-        res = self.get_response()
-        return None if res == 'none' else res
-    
-    def keys(self, pattern):
-        """
-        >>> r = Redis(db=9)
-        >>> r.flush()
-        'OK'
-        >>> r.set('a', 'a')
-        'OK'
-        >>> r.keys('a*')
-        [u'a']
-        >>> r.set('a2', 'a')
-        'OK'
-        >>> r.keys('a*')
-        [u'a', u'a2']
-        >>> r.delete('a2')
-        1
-        >>> r.keys('sjdfhskjh*')
-        []
-        >>>
-        """
-        self.connect()
-        self._write('KEYS %s\r\n' % pattern)
-        return self.get_response().split()
-    
-    def randomkey(self):
-        """
-        >>> r = Redis(db=9)
-        >>> r.set('a', 'a')
-        'OK'
-        >>> isinstance(r.randomkey(), str)
-        True
-        >>> 
-        """
-        #raise NotImplementedError("Implemented but buggy, do not use.")
-        self.connect()
-        self._write('RANDOMKEY\r\n')
-        return self.get_response()
-    
-    def rename(self, src, dst, preserve=False):
-        """
-        >>> r = Redis(db=9)
-        >>> try:
-        ...     r.rename('a', 'a')
-        ... except ResponseError, e:
-        ...     print e
-        source and destination objects are the same
-        >>> r.rename('a', 'b')
-        'OK'
-        >>> try:
-        ...     r.rename('a', 'b')
-        ... except ResponseError, e:
-        ...     print e
-        no such key
-        >>> r.set('a', 1)
-        'OK'
-        >>> r.rename('b', 'a', preserve=True)
-        0
-        >>> 
-        """
-        self.connect()
-        if preserve:
-            self._write('RENAMENX %s %s\r\n' % (src, dst))
-            return self.get_response()
-        else:
-            self._write('RENAME %s %s\r\n' % (src, dst))
-            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(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.push('l', 'a')
-        'OK'
-        >>> r.set('a', 'a')
-        'OK'
-        >>> try:
-        ...     r.push('a', 'a')
-        ... except ResponseError, e:
-        ...     print e
-        Operation against a key holding the wrong kind of value
-        >>> 
-        """
-        self.connect()
-        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(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.push('l', 'a')
-        'OK'
-        >>> r.llen('l')
-        1
-        >>> r.push('l', 'a')
-        'OK'
-        >>> r.llen('l')
-        2
-        >>> 
-        """
-        self.connect()
-        self._write('LLEN %s\r\n' % name)
-        return self.get_response()
-
-    def lrange(self, name, start, end):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.lrange('l', 0, 1)
-        []
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.lrange('l', 0, 1)
-        [u'aaa']
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.lrange('l', 0, 0)
-        [u'aaa']
-        >>> r.lrange('l', 0, 1)
-        [u'aaa', u'bbb']
-        >>> r.lrange('l', -1, 0)
-        []
-        >>> r.lrange('l', -1, -1)
-        [u'bbb']
-        >>> 
-        """
-        self.connect()
-        self._write('LRANGE %s %s %s\r\n' % (name, start, end))
-        return self.get_response()
-        
-    def ltrim(self, name, start, end):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('l')
-        1
-        >>> try:
-        ...     r.ltrim('l', 0, 1)
-        ... except ResponseError, e:
-        ...     print e
-        no such key
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.push('l', 'ccc')
-        'OK'
-        >>> r.ltrim('l', 0, 1)
-        'OK'
-        >>> r.llen('l')
-        2
-        >>> r.ltrim('l', 99, 95)
-        'OK'
-        >>> r.llen('l')
-        0
-        >>> 
-        """
-        self.connect()
-        self._write('LTRIM %s %s %s\r\n' % (name, start, end))
-        return self.get_response()
-    
-    def lindex(self, name, index):
-        """
-        >>> r = Redis(db=9)
-        >>> res = r.delete('l')
-        >>> r.lindex('l', 0)
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.lindex('l', 0)
-        u'aaa'
-        >>> r.lindex('l', 2)
-        >>> r.push('l', 'ccc')
-        'OK'
-        >>> r.lindex('l', 1)
-        u'ccc'
-        >>> r.lindex('l', -1)
-        u'ccc'
-        >>> 
-        """
-        self.connect()
-        self._write('LINDEX %s %s\r\n' % (name, index))
-        return self.get_response()
-        
-    def pop(self, name, tail=False):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.pop('l')
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.pop('l')
-        u'aaa'
-        >>> r.pop('l')
-        u'bbb'
-        >>> r.pop('l')
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.pop('l', tail=True)
-        u'bbb'
-        >>> r.pop('l')
-        u'aaa'
-        >>> r.pop('l')
-        >>> 
-        """
-        self.connect()
-        self._write('%s %s\r\n' % ('RPOP' if tail else 'LPOP', name))
-        return self.get_response()
-    
-    def lset(self, name, index, value):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('l')
-        1
-        >>> try:
-        ...     r.lset('l', 0, 'a')
-        ... except ResponseError, e:
-        ...     print e
-        no such key
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> try:
-        ...     r.lset('l', 1, 'a')
-        ... except ResponseError, e:
-        ...     print e
-        index out of range
-        >>> r.lset('l', 0, 'bbb')
-        'OK'
-        >>> r.lrange('l', 0, 1)
-        [u'bbb']
-        >>> 
-        """
-        self.connect()
-        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(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.lrem('l', 'aaa')
-        2
-        >>> r.lrange('l', 0, 10)
-        [u'bbb']
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.lrem('l', 'aaa', 1)
-        1
-        >>> r.lrem('l', 'aaa', 1)
-        1
-        >>> r.lrem('l', 'aaa', 1)
-        0
-        >>> 
-        """
-        self.connect()
-        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(db=9)
-        >>> r.delete('l')
-        1
-        >>> r.push('l', 'ccc')
-        'OK'
-        >>> r.push('l', 'aaa')
-        'OK'
-        >>> r.push('l', 'ddd')
-        'OK'
-        >>> r.push('l', 'bbb')
-        'OK'
-        >>> r.sort('l', alpha=True)
-        [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')
-        [Decimal("0.25"), Decimal("0.333333333333"), Decimal("0.5"), Decimal("1.0")]
-        >>> r.sort('l', desc=True)
-        [Decimal("1.0"), Decimal("0.5"), Decimal("0.333333333333"), Decimal("0.25")]
-        >>> r.sort('l', desc=True, start=2, num=1)
-        [Decimal("0.333333333333")]
-        >>> r.set('weight_0.5', 10)
-        'OK'
-        >>> r.sort('l', desc=True, by='weight_*')
-        [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_*')
-        [Decimal("99.0"), Decimal("99.5"), Decimal("99.6666666667"), Decimal("99.75")]
-        >>> r.sort('l', desc=True, by='weight_*', get='test_*')
-        [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]
-        >>> 
-        """
-        stmt = ['SORT', name]
-        if by:
-            stmt.append("BY %s" % by)
-        if start and num:
-            stmt.append("LIMIT %s %s" % (start, num))
-        if get is None:
-            pass
-        elif isinstance(get, basestring):
-            stmt.append("GET %s" % get)
-        elif isinstance(get, list) or isinstance(get, tuple):
-            for g in get:
-                stmt.append("GET %s" % g)
-        else:
-            raise RedisError("Invalid parameter 'get' for Redis sort")
-        if desc:
-            stmt.append("DESC")
-        if alpha:
-            stmt.append("ALPHA")
-        self.connect()
-        self._write(' '.join(stmt + ["\r\n"]))
-        return self.get_response()
-    
-    def sadd(self, name, value):
-        """
-        >>> r = Redis(db=9)
-        >>> res = r.delete('s')
-        >>> r.sadd('s', 'a')
-        1
-        >>> r.sadd('s', 'b')
-        1
-        >>> 
-        """
-        self.connect()
-        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(db=9)
-        >>> r.delete('s')
-        1
-        >>> r.srem('s', 'aaa')
-        0
-        >>> r.sadd('s', 'b')
-        1
-        >>> r.srem('s', 'b')
-        1
-        >>> r.sismember('s', 'b')
-        0
-        >>> 
-        """
-        self.connect()
-        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(db=9)
-        >>> r.delete('s')
-        1
-        >>> r.sismember('s', 'b')
-        0
-        >>> r.sadd('s', 'a')
-        1
-        >>> r.sismember('s', 'b')
-        0
-        >>> r.sismember('s', 'a')
-        1
-        >>>
-        """
-        self.connect()
-        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(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
-        >>> try:
-        ...     r.sinter()
-        ... except ResponseError, e:
-        ...     print e
-        wrong number of arguments
-        >>> try:
-        ...     r.sinter('l')
-        ... except ResponseError, e:
-        ...     print e
-        Operation against a key holding the wrong kind of value
-        >>> r.sinter('s1', 's2', 's3')
-        set([])
-        >>> r.sinter('s1', 's2')
-        set([u'a'])
-        >>> 
-        """
-        self.connect()
-        self._write('SINTER %s\r\n' % ' '.join(args))
-        return set(self.get_response())
-    
-    def sinterstore(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.sinterstore('s_s', 's1', 's2', 's3')
-        0
-        >>> r.sinterstore('s_s', 's1', 's2')
-        1
-        >>> r.smembers('s_s')
-        set([u'a'])
-        >>> 
-        """
-        self.connect()
-        self._write('SINTERSTORE %s %s\r\n' % (dest, ' '.join(args)))
-        return self.get_response()
-
-    def smembers(self, name):
-        """
-        >>> r = Redis(db=9)
-        >>> r.delete('s')
-        1
-        >>> r.sadd('s', 'a')
-        1
-        >>> r.sadd('s', 'b')
-        1
-        >>> try:
-        ...     r.smembers('l')
-        ... except ResponseError, e:
-        ...     print e
-        Operation against a key holding the wrong kind of value
-        >>> r.smembers('s')
-        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(db=9)
-        >>> r.delete('a')
-        1
-        >>> r.select(10)
-        'OK'
-        >>> r.set('a', 1)
-        'OK'
-        >>> r.select(9)
-        'OK'
-        >>> r.get('a')
-        >>> 
-        """
-        self.connect()
-        self._write('SELECT %s\r\n' % db)
-        return self.get_response()
-    
-    def move(self, name, db):
-        """
-        >>> r = Redis(db=9)
-        >>> r.set('a', 'a')
-        'OK'
-        >>> r.select(10)
-        'OK'
-        >>> if r.get('a'):
-        ...     r.delete('a')
-        ... else:
-        ...     print 1
-        1
-        >>> r.select(9)
-        'OK'
-        >>> r.move('a', 10)
-        1
-        >>> r.get('a')
-        >>> r.select(10)
-        'OK'
-        >>> r.get('a')
-        u'a'
-        >>> r.select(9)
-        'OK'
-        >>> 
-        """
-        self.connect()
-        self._write('MOVE %s %s\r\n' % (name, db))
-        return self.get_response()
-    
-    def save(self, background=False):
-        """
-        >>> r = Redis(db=9)
-        >>> r.save()
-        'OK'
-        >>> try:
-        ...     resp = r.save(background=True)
-        ... except ResponseError, e:
-        ...     assert str(e) == 'background save already in progress', str(e)
-        ... else:
-        ...     assert resp == 'OK'
-        >>> 
-        """
-        self.connect()
-        if background:
-            self._write('BGSAVE\r\n')
-        else:
-            self._write('SAVE\r\n')
-        return self.get_response()
-        
-    def lastsave(self):
-        """
-        >>> import time
-        >>> r = Redis(db=9)
-        >>> t = int(time.time())
-        >>> r.save()
-        'OK'
-        >>> r.lastsave() >= t
-        True
-        >>> 
-        """
-        self.connect()
-        self._write('LASTSAVE\r\n')
-        return self.get_response()
-    
-    def flush(self, all_dbs=False):
-        """
-        >>> r = Redis(db=9)
-        >>> r.flush()
-        'OK'
-        >>> # r.flush(all_dbs=True)
-        >>> 
-        """
-        self.connect()
-        self._write('%s\r\n' % ('FLUSHALL' if all_dbs else 'FLUSHDB'))
-        return self.get_response()
-    
-    def info(self):
-        """
-        >>> r = Redis(db=9)
-        >>> info = r.info()
-        >>> info and isinstance(info, dict)
-        True
-        >>> isinstance(info.get('connected_clients'), int)
-        True
-        >>> 
-        """
-        self.connect()
-        self._write('INFO\r\n')
-        info = dict()
-        for l in self.get_response().split('\r\n'):
-            if not l:
-                continue
-            k, v = l.split(':', 1)
-            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:])
-        if c == '+':
-            return data[1:]
-        if c == '*':
-            try:
-                num = int(data[1:])
-            except (TypeError, ValueError):
-                raise InvalidResponse("Cannot convert multi-response header '%s' to integer" % data)
-            result = list()
-            for i in range(num):
-                result.append(self._get_value())
-            return result
-        return self._get_value(data)
-    
-    def _get_value(self, data=None):
-        data = data or self._read().strip()
-        if data == '$-1':
-            return None
-        try:
-            c, i = data[0], (int(data[1:]) if data.find('.') == -1 else float(data[1:]))
-        except ValueError:
-            raise InvalidResponse("Cannot convert data '%s' to integer" % data)
-        if c == ':':
-            return i
-        if c != '$':
-            raise InvalidResponse("Unkown response prefix for '%s'" % data)
-        buf = []
-        while True:
-            data = self._read()
-            i -= len(data)
-            buf.append(data)
-            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):
-            try:
-                self._sock.close()
-            except socket.error:
-                pass
-        self._sock = None
-        self._fp = None
-            
-    def connect(self):
-        """
-        >>> r = Redis(db=9)
-        >>> r.connect()
-        >>> isinstance(r._sock, socket.socket)
-        True
-        >>> r.disconnect()
-        >>> 
-        """
-        if isinstance(self._sock, socket.socket):
-            return
-        try:
-            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
-            sock.connect((self.host, self.port))
-        except socket.error, e:
-            raise ConnectionError("Error %s connecting to %s:%s. %s." % (e.args[0], self.host, self.port, e.args[1]))
-        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()
-