Navigation

Source code for ledis.client

from__future__importwith_statementimportdatetimeimporttimeasmod_timefromitertoolsimportchain,starmapfromledis._compatimport(b,izip,imap,iteritems,basestring,long,nativestr,bytes)fromledis.connectionimportConnectionPool,UnixDomainSocketConnection,Tokenfromledis.exceptionsimport(ConnectionError,DataError,LedisError,ResponseError,TxNotBeginError)SYM_EMPTY=b('')deflist_or_args(keys,args):# returns a single list combining keys and argstry:iter(keys)# a string or bytes instance can be iterated, but indicates# keys wasn't passed as a listifisinstance(keys,(basestring,bytes)):keys=[keys]exceptTypeError:keys=[keys]ifargs:keys.extend(args)returnkeysdefstring_keys_to_dict(key_string,callback):returndict.fromkeys(key_string.split(),callback)defdict_merge(*dicts):merged={}[merged.update(d)fordindicts]returnmergeddefpairs_to_dict(response):"Create a dict given a list of key/value pairs"it=iter(response)returndict(izip(it,it))defzset_score_pairs(response,**options):""" If ``withscores`` is specified in the options, return the response as a list of (value, score) pairs """ifnotresponseornotoptions['withscores']:returnresponseit=iter(response)returnlist(izip(it,imap(int,it)))defint_or_none(response):ifresponseisNone:returnNonereturnint(response)defparse_info(response):info={}response=nativestr(response)defget_value(value):if','notinvalueor'='notinvalue:try:if'.'invalue:returnfloat(value)else:returnint(value)exceptValueError:returnvalueforlineinresponse.splitlines():iflineandnotline.startswith('#'):ifline.find(':')!=-1:key,value=line.split(':',1)info[key]=get_value(value)returninfo# def parse_lscan(response, )

[docs]deffrom_url(cls,url,db=None,**kwargs):""" Return a Ledis client object configured from the given URL. For example:: ledis://localhost:6380/0 unix:///path/to/socket.sock?db=0 There are several ways to specify a database number. The parse function will return the first specified option: 1. A ``db`` querystring option, e.g. ledis://localhost?db=0 2. If using the ledis:// scheme, the path argument of the url, e.g. ledis://localhost/0 3. The ``db`` argument to this function. If none of these options are specified, db=0 is used. Any additional querystring arguments and keyword arguments will be passed along to the ConnectionPool class's initializer. In the case of conflicting arguments, querystring arguments always win. """connection_pool=ConnectionPool.from_url(url,db=db,**kwargs)returncls(connection_pool=connection_pool)

[docs]defexecute_command(self,*args,**options):"Execute a command and return a parsed response"pool=self.connection_poolcommand_name=args[0]connection=pool.get_connection(command_name,**options)try:connection.send_command(*args)returnself.parse_response(connection,command_name,**options)exceptConnectionError:connection.disconnect()connection.send_command(*args)returnself.parse_response(connection,command_name,**options)finally:pool.release(connection)

[docs]defparse_response(self,connection,command_name,**options):"Parses a response from the Ledis server"response=connection.read_response()ifcommand_nameinself.response_callbacks:returnself.response_callbacks[command_name](response,**options)returnresponse

#### SERVER INFORMATION ####

[docs]defecho(self,value):"Echo the string back from the server"returnself.execute_command('ECHO',value)

[docs]defdecr(self,name,amount=1):""" Decrements the value of ``key`` by ``amount``. If no key exists, the value will be initialized as 0 - ``amount`` """returnself.execute_command('DECRBY',name,amount)

[docs]defdecrby(self,name,amount=1):""" Decrements the value of ``key`` by ``amount``. If no key exists, the value will be initialized as 0 - ``amount`` """returnself.decr(name,amount)

[docs]defdelete(self,*names):"Delete one or more keys specified by ``names``"returnself.execute_command('DEL',*names)

[docs]defexpire(self,name,time):""" Set an expire flag on key ``name`` for ``time`` seconds. ``time`` can be represented by an integer or a Python timedelta object. """ifisinstance(time,datetime.timedelta):time=time.seconds+time.days*24*3600returnself.execute_command('EXPIRE',name,time)

[docs]defexpireat(self,name,when):""" Set an expire flag on key ``name``. ``when`` can be represented as an integer indicating unix time or a Python datetime object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('EXPIREAT',name,when)

[docs]defget(self,name):""" Return the value at key ``name``, or None if the key doesn't exist """returnself.execute_command('GET',name)

def__getitem__(self,name):""" Return the value at key ``name``, raises a KeyError if the key doesn't exist. """value=self.get(name)ifvalue:returnvalueraiseKeyError(name)

[docs]defgetset(self,name,value):""" Set the value at key ``name`` to ``value`` if key doesn't exist Return the value at key ``name`` atomically """returnself.execute_command('GETSET',name,value)

[docs]defincr(self,name,amount=1):""" Increments the value of ``key`` by ``amount``. If no key exists, the value will be initialized as ``amount`` """returnself.execute_command('INCRBY',name,amount)

[docs]defincrby(self,name,amount=1):""" Increments the value of ``key`` by ``amount``. If no key exists, the value will be initialized as ``amount`` """# An alias for ``incr()``, because it is already implemented# as INCRBY ledis command.returnself.incr(name,amount)

[docs]defmset(self,*args,**kwargs):""" Sets key/values based on a mapping. Mapping can be supplied as a single dictionary argument or as kwargs. """ifargs:iflen(args)!=1ornotisinstance(args[0],dict):raiseLedisError('MSET requires **kwargs or a single dict arg')kwargs.update(args[0])items=[]forpairiniteritems(kwargs):items.extend(pair)returnself.execute_command('MSET',*items)

[docs]defset(self,name,value):""" Set the value of key ``name`` to ``value``. """pieces=[name,value]returnself.execute_command('SET',*pieces)

[docs]defsetnx(self,name,value):"Set the value of key ``name`` to ``value`` if key doesn't exist"returnself.execute_command('SETNX',name,value)

[docs]deflindex(self,name,index):""" Return the item from list ``name`` at position ``index`` Negative indexes are supported and will return an item at the end of the list """returnself.execute_command('LINDEX',name,index)

[docs]defllen(self,name):"Return the length of the list ``name``"returnself.execute_command('LLEN',name)

[docs]deflpop(self,name):"Remove and return the first item of the list ``name``"returnself.execute_command('LPOP',name)

[docs]deflpush(self,name,*values):"Push ``values`` onto the head of the list ``name``"returnself.execute_command('LPUSH',name,*values)

[docs]deflrange(self,name,start,end):""" Return a slice of the list ``name`` between position ``start`` and ``end`` ``start`` and ``end`` can be negative numbers just like Python slicing notation """returnself.execute_command('LRANGE',name,start,end)

[docs]defrpop(self,name):"Remove and return the last item of the list ``name``"returnself.execute_command('RPOP',name)

[docs]defrpush(self,name,*values):"Push ``values`` onto the tail of the list ``name``"returnself.execute_command('RPUSH',name,*values)

# SPECIAL COMMANDS SUPPORTED BY LEDISDB

[docs]deflclear(self,name):"Delete the key of ``name``"returnself.execute_command("LCLEAR",name)

[docs]deflexpire(self,name,time):""" Set an expire flag on key ``name`` for ``time`` seconds. ``time`` can be represented by an integer or a Python timedelta object. """ifisinstance(time,datetime.timedelta):time=time.seconds+time.days*24*3600returnself.execute_command("LEXPIRE",name,time)

[docs]deflexpireat(self,name,when):""" Set an expire flag on key ``name``. ``when`` can be represented as an integer indicating unix time or a Python datetime object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('LEXPIREAT',name,when)

[docs]deflttl(self,name):"Returns the number of seconds until the key ``name`` will expire"returnself.execute_command('LTTL',name)

[docs]deflpersist(self,name):"Removes an expiration on ``name``"returnself.execute_command('LPERSIST',name)

[docs]defsadd(self,name,*values):"Add ``value(s)`` to set ``name``"returnself.execute_command('SADD',name,*values)

[docs]defscard(self,name):"Return the number of elements in set ``name``"returnself.execute_command('SCARD',name)

[docs]defsdiff(self,keys,*args):"Return the difference of sets specified by ``keys``"args=list_or_args(keys,args)returnself.execute_command('SDIFF',*args)

[docs]defsdiffstore(self,dest,keys,*args):""" Store the difference of sets specified by ``keys`` into a new set named ``dest``. Returns the number of keys in the new set. """args=list_or_args(keys,args)returnself.execute_command('SDIFFSTORE',dest,*args)

[docs]defsinter(self,keys,*args):"Return the intersection of sets specified by ``keys``"args=list_or_args(keys,args)returnself.execute_command('SINTER',*args)

[docs]defsinterstore(self,dest,keys,*args):""" Store the intersection of sets specified by ``keys`` into a new set named ``dest``. Returns the number of keys in the new set. """args=list_or_args(keys,args)returnself.execute_command('SINTERSTORE',dest,*args)

[docs]defsismember(self,name,value):"Return a boolean indicating if ``value`` is a member of set ``name``"returnself.execute_command('SISMEMBER',name,value)

[docs]defsmembers(self,name):"Return all members of the set ``name``"returnself.execute_command('SMEMBERS',name)

[docs]defsrem(self,name,*values):"Remove ``values`` from set ``name``"returnself.execute_command('SREM',name,*values)

[docs]defsunion(self,keys,*args):"Return the union of sets specified by ``keys``"args=list_or_args(keys,args)returnself.execute_command('SUNION',*args)

[docs]defsunionstore(self,dest,keys,*args):""" Store the union of sets specified by ``keys`` into a new set named ``dest``. Returns the number of keys in the new set. """args=list_or_args(keys,args)returnself.execute_command('SUNIONSTORE',dest,*args)

[docs]defsexpire(self,name,time):""" Set an expire flag on key name for time milliseconds. time can be represented by an integer or a Python timedelta object. """ifisinstance(time,datetime.timedelta):time=time.seconds+time.days*24*3600returnself.execute_command('SEXPIRE',name,time)

[docs]defsexpireat(self,name,when):""" Set an expire flag on key name. when can be represented as an integer representing unix time in milliseconds (unix time * 1000) or a Python datetime object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('SEXPIREAT',name,when)

[docs]defsttl(self,name):"Returns the number of seconds until the key name will expire"returnself.execute_command('STTL',name)

[docs]defspersist(self,name):"Removes an expiration on name"returnself.execute_command('SPERSIST',name)

[docs]defzadd(self,name,*args,**kwargs):""" Set any number of score, element-name pairs to the key ``name``. Pairs can be specified in two ways: As *args, in the form of: score1, name1, score2, name2, ... or as **kwargs, in the form of: name1=score1, name2=score2, ... The following example would add four values to the 'my-key' key: ledis.zadd('my-key', 1.1, 'name1', 2.2, 'name2', name3=3.3, name4=4.4) """pieces=[]ifargs:iflen(args)%2!=0:raiseLedisError("ZADD requires an equal number of ""values and scores")pieces.extend(args)forpairiniteritems(kwargs):pieces.append(pair[1])pieces.append(pair[0])returnself.execute_command('ZADD',name,*pieces)

[docs]defzcard(self,name):"Return the number of elements in the sorted set ``name``"returnself.execute_command('ZCARD',name)

[docs]defzcount(self,name,min,max):""" Return the number of elements in the sorted set at key ``name`` with a score between ``min`` and ``max``. The min and max arguments have the same semantic as described for ZRANGEBYSCORE. """returnself.execute_command('ZCOUNT',name,min,max)

[docs]defzincrby(self,name,value,amount=1):"Increment the score of ``value`` in sorted set ``name`` by ``amount``"returnself.execute_command('ZINCRBY',name,amount,value)

[docs]defzrange(self,name,start,end,desc=False,withscores=False):""" Return a range of values from sorted set ``name`` between ``start`` and ``end`` sorted in ascending order. ``start`` and ``end`` can be negative, indicating the end of the range. ``desc`` a boolean indicating whether to sort the results descendingly ``withscores`` indicates to return the scores along with the values. The return type is a list of (value, score) pairs """ifdesc:returnself.zrevrange(name,start,end,withscores)pieces=['ZRANGE',name,start,end]ifwithscores:pieces.append('withscores')options={'withscores':withscores}returnself.execute_command(*pieces,**options)

[docs]defzrangebyscore(self,name,min,max,start=None,num=None,withscores=False):""" Return a range of values from the sorted set ``name`` with scores between ``min`` and ``max``. If ``start`` and ``num`` are specified, then return a slice of the range. ``withscores`` indicates to return the scores along with the values. The return type is a list of (value, score) pairs """if(startisnotNoneandnumisNone)or \
(numisnotNoneandstartisNone):raiseLedisError("``start`` and ``num`` must both be specified")pieces=['ZRANGEBYSCORE',name,min,max]ifstartisnotNoneandnumisnotNone:pieces.extend(['LIMIT',start,num])ifwithscores:pieces.append('withscores')options={'withscores':withscores}returnself.execute_command(*pieces,**options)

[docs]defzrank(self,name,value):""" Returns a 0-based value indicating the rank of ``value`` in sorted set ``name`` """returnself.execute_command('ZRANK',name,value)

[docs]defzrem(self,name,*values):"Remove member ``values`` from sorted set ``name``"returnself.execute_command('ZREM',name,*values)

[docs]defzremrangebyrank(self,name,min,max):""" Remove all elements in the sorted set ``name`` with ranks between ``min`` and ``max``. Values are 0-based, ordered from smallest score to largest. Values can be negative indicating the highest scores. Returns the number of elements removed """returnself.execute_command('ZREMRANGEBYRANK',name,min,max)

[docs]defzremrangebyscore(self,name,min,max):""" Remove all elements in the sorted set ``name`` with scores between ``min`` and ``max``. Returns the number of elements removed. """returnself.execute_command('ZREMRANGEBYSCORE',name,min,max)

[docs]defzrevrange(self,name,start,num,withscores=False):""" Return a range of values from sorted set ``name`` between ``start`` and ``num`` sorted in descending order. ``start`` and ``num`` can be negative, indicating the end of the range. ``withscores`` indicates to return the scores along with the values The return type is a list of (value, score) pairs """pieces=['ZREVRANGE',name,start,num]ifwithscores:pieces.append('withscores')options={'withscores':withscores}returnself.execute_command(*pieces,**options)

[docs]defzrevrangebyscore(self,name,min,max,start=None,num=None,withscores=False):""" Return a range of values from the sorted set ``name`` with scores between ``min`` and ``max`` in descending order. If ``start`` and ``num`` are specified, then return a slice of the range. ``withscores`` indicates to return the scores along with the values. The return type is a list of (value, score) pairs """if(startisnotNoneandnumisNone)or \
(numisnotNoneandstartisNone):raiseLedisError("``start`` and ``num`` must both be specified")pieces=['ZREVRANGEBYSCORE',name,min,max]ifstartisnotNoneandnumisnotNone:pieces.extend(['LIMIT',start,num])ifwithscores:pieces.append('withscores')options={'withscores':withscores}returnself.execute_command(*pieces,**options)

[docs]defzrevrank(self,name,value):""" Returns a 0-based value indicating the descending rank of ``value`` in sorted set ``name`` """returnself.execute_command('ZREVRANK',name,value)

[docs]defzscore(self,name,value):"Return the score of element ``value`` in sorted set ``name``"returnself.execute_command('ZSCORE',name,value)

[docs]defzexpireat(self,name,when):""" Set an expire flag on key name for time seconds. time can be represented by an integer or a Python timedelta object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('ZEXPIREAT',name,when)

[docs]defzttl(self,name):"Returns the number of seconds until the key name will expire"returnself.execute_command('ZTTL',name)

[docs]defzpersist(self,name):"Removes an expiration on name"returnself.execute_command('ZPERSIST',name)

[docs]defhexists(self,name,key):"Returns a boolean indicating if ``key`` exists within hash ``name``"returnself.execute_command('HEXISTS',name,key)

[docs]defhget(self,name,key):"Return the value of ``key`` within the hash ``name``"returnself.execute_command('HGET',name,key)

[docs]defhgetall(self,name):"Return a Python dict of the hash's name/value pairs"returnself.execute_command('HGETALL',name)

[docs]defhincrby(self,name,key,amount=1):"Increment the value of ``key`` in hash ``name`` by ``amount``"returnself.execute_command('HINCRBY',name,key,amount)

[docs]defhkeys(self,name):"Return the list of keys within hash ``name``"returnself.execute_command('HKEYS',name)

[docs]defhlen(self,name):"Return the number of elements in hash ``name``"returnself.execute_command('HLEN',name)

[docs]defhmget(self,name,keys,*args):"Returns a list of values ordered identically to ``keys``"args=list_or_args(keys,args)returnself.execute_command('HMGET',name,*args)

[docs]defhmset(self,name,mapping):""" Sets each key in the ``mapping`` dict to its corresponding value in the hash ``name`` """ifnotmapping:raiseDataError("'hmset' with 'mapping' of length 0")items=[]forpairiniteritems(mapping):items.extend(pair)returnself.execute_command('HMSET',name,*items)

[docs]defhset(self,name,key,value):""" Set ``key`` to ``value`` within hash ``name`` Returns 1 if HSET created a new field, otherwise 0 """returnself.execute_command('HSET',name,key,value)

[docs]defhvals(self,name):"Return the list of values within hash ``name``"returnself.execute_command('HVALS',name)

[docs]defhexpire(self,name,time):""" Set an expire flag on key name for time milliseconds. time can be represented by an integer or a Python timedelta object. """ifisinstance(time,datetime.timedelta):time=time.seconds+time.days*24*3600returnself.execute_command('HEXPIRE',name,time)

[docs]defhexpireat(self,name,when):""" Set an expire flag on key name. when can be represented as an integer representing unix time in milliseconds (unix time * 1000) or a Python datetime object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('HEXPIREAT',name,when)

[docs]defhttl(self,name):"Returns the number of seconds until the key name will expire"returnself.execute_command('HTTL',name)

[docs]defhpersist(self,name):"Removes an expiration on name"returnself.execute_command('HPERSIST',name)

[docs]defbmsetbit(self,name,*args):""" Set any number of offset, value pairs to the key ``name``. Pairs can be specified in the following way: offset1, value1, offset2, value2, ... """pieces=[]ifargs:iflen(args)%2!=0:raiseLedisError("BMSETBIT requires an equal number of ""offset and value")pieces.extend(args)returnself.execute_command("BMSETBIT",name,*pieces)

defbcount(self,key,start=None,end=None):""params=[key]ifstartisnotNoneandendisnotNone:params.append(start)params.append(end)elif(startisnotNoneandendisNone)or \
(startisNoneandendisnotNone):raiseLedisError("Both start and end must be specified")returnself.execute_command("BCOUNT",*params)

[docs]defbopt(self,operation,dest,*keys):""" Perform a bitwise operation using ``operation`` between ``keys`` and store the result in ``dest``. ``operation`` is one of `and`, `or`, `xor`, `not`. """returnself.execute_command('BOPT',operation,dest,*keys)

[docs]defbexpireat(self,name,when):""" Set an expire flag on key name for time seconds. time can be represented by an integer or a Python timedelta object. """ifisinstance(when,datetime.datetime):when=int(mod_time.mktime(when.timetuple()))returnself.execute_command('BEXPIREAT',name,when)

[docs]defbttl(self,name):"Returns the number of seconds until the key name will expire"returnself.execute_command('BTTL',name)

[docs]defbpersist(self,name):"Removes an expiration on name"returnself.execute_command('BPERSIST',name)

classTransaction(Ledis):def__init__(self,connection_pool,response_callbacks):self.connection_pool=connection_poolself.response_callbacks=response_callbacksself.connection=Nonedefexecute_command(self,*args,**options):"Execute a command and return a parsed response"command_name=args[0]connection=self.connectionifself.connectionisNone:raiseTxNotBeginErrortry:connection.send_command(*args)returnself.parse_response(connection,command_name,**options)exceptConnectionError:connection.disconnect()connection.send_command(*args)returnself.parse_response(connection,command_name,**options)defbegin(self):self.connection=self.connection_pool.get_connection('begin')returnself.execute_command("BEGIN")defcommit(self):res=self.execute_command("COMMIT")self.connection_pool.release(self.connection)self.connection=Nonereturnresdefrollback(self):res=self.execute_command("ROLLBACK")self.connection_pool.release(self.connection)self.connection=Nonereturnres