Skip to content

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also .

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also .
  • 2 commits
  • 2 files changed
  • 0 commit comments
  • 1 contributor
Commits on Sep 21, 2011
@rlotun Added support for OBJECT command. 4d89fb2
@rlotun Support for variadic commands introduced in 2.4.
A variable number of values can now be passed to the following
commands: SADD, HDEL, SREM, ZREM, ZADD, L/RPUSH to bring support
in line with Redis 2.4.

A caveat - for ZADD the original implementation of txRedis broke
from convention of 'ZADD key score value' to have the method accept
'zadd(key, value, score)' (for whatever reason). This mode is still
supported for backwards compatibility but if a sequence of arguments
are passed, we now support a more Redis-like convention of
'zadd(key, score1, value1, score2, value2)'.
f4602a2
Showing with 230 additions and 24 deletions.
  1. +117 −24 txredis/protocol.py
  2. +113 −0 txredis/test/test_redis.py
View
141 txredis/protocol.py
@@ -97,6 +97,8 @@ class InvalidResponse(RedisError):
class InvalidData(RedisError):
pass
+class InvalidCommand(RedisError):
+ pass
class RedisBase(protocol.Protocol, policies.TimeoutMixin, object):
"""The main Redis client."""
@@ -553,9 +555,30 @@ def get_type(self, key):
Determine the type stored at key
"""
self._send('TYPE', key)
- res = self.getResponse()
- # return None if res == 'none' else res
- return res
+ return self.getResponse()
+
+ def get_object(self, key, refcount=False, encoding=False, idletime=False):
+ """
+ Inspect the internals of Redis objects.
+ @param key : The Redis key you want to inspect
+ @param refcount : Returns the number of refereces of the value
+ associated with the specified key.
+ @param encoding : Returns the kind of internal representation for value.
+ @param idletime Returns the number of seconds since the object stored
+ at the specified key is idle. (Currently the actual
+ resolution is 10 seconds.)
+ """
+ subcommand = ''
+ if idletime:
+ subcommand = 'IDLETIME'
+ elif encoding:
+ subcommand = 'ENCODING'
+ elif refcount:
+ subcommand = 'REFCOUNT'
+ if not subcommand:
+ raise InvalidCommand('Need a subcommand')
+ self._send('OBJECT', subcommand, key)
+ return self.getResponse()
# Commands operating on the key space
def keys(self, pattern):
@@ -697,12 +720,34 @@ def push(self, key, value, tail=False, no_create=False):
else:
return self.lpush(key, value)
- def lpush(self, key, value):
- self._send('LPUSH', key, value)
+ def lpush(self, key, *values, **kwargs):
+ """
+ Add string to head of list.
+ @param key : List key
+ @param values : Sequence of values to push
+ @param value : For backwards compatibility, a single value.
+ """
+ if not kwargs:
+ self._send('LPUSH', key, *values)
+ elif 'value' in kwargs:
+ self._send('LPUSH', key, kwargs['value'])
+ else:
+ raise InvalidCommand('Need arguments for LPUSH')
return self.getResponse()
- def rpush(self, key, value):
- self._send('RPUSH', key, value)
+ def rpush(self, key, *values, **kwargs):
+ """
+ Add string to end of list.
+ @param key : List key
+ @param values : Sequence of values to push
+ @param value : For backwards compatibility, a single value.
+ """
+ if not kwargs:
+ self._send('RPUSH', key, *values)
+ elif 'value' in kwargs:
+ self._send('RPUSH', key, kwargs['value'])
+ else:
+ raise InvalidCommand('Need arguments for RPUSH')
return self.getResponse()
def lpushx(self, key, value):
@@ -991,18 +1036,34 @@ def _list_to_set(self, res):
return set(res)
return res
- def sadd(self, key, value):
+ def sadd(self, key, *values, **kwargs):
"""
Add a member to a set
- """
- self._send('SADD', key, value)
+ @param key : SET key to add values to.
+ @param values : sequence of values to add to set
+ @param value : For backwards compatibility, add one value.
+ """
+ if not kwargs:
+ self._send('SADD', key, *values)
+ elif 'value' in kwargs:
+ self._send('SADD', key, kwargs['value'])
+ else:
+ raise InvalidCommand('Need arguments for SADD')
return self.getResponse()
- def srem(self, key, value):
+ def srem(self, key, *values, **kwargs):
"""
Remove a member from a set
- """
- self._send('SREM', key, value)
+ @param key : Set key
+ @param values : Sequence of values to remove
+ @param value : For backwards compatibility, single value to remove.
+ """
+ if not kwargs:
+ self._send('SREM', key, *values)
+ elif 'value' in kwargs:
+ self._send('SREM', key, kwargs['value'])
+ else:
+ raise InvalidCommand('Need arguments for SREM')
return self.getResponse()
def spop(self, key):
@@ -1350,11 +1411,19 @@ def hexists(self, key, field):
self._send('HEXISTS', key, field)
return self.getResponse()
- def hdel(self, key, field):
+ def hdel(self, key, *fields, **kwargs):
"""
Removes field from the hash stored at key.
- """
- self._send('HDEL', key, field)
+ @param key : Hash key
+ @param fields : Sequence of fields to remvoe
+ @param field : For backwards compatibility. Single field to remove.
+ """
+ if not kwargs:
+ self._send('HDEL', key, *fields)
+ elif 'field' in kwargs:
+ self._send('HDEL', key, field)
+ else:
+ raise InvalidCommand('Need arguments for HDEL')
return self.getResponse()
hdelete = hdel # backwards compat for older txredis
@@ -1405,18 +1474,42 @@ def publish(self, channel, message):
# ZREMRANGEBYRANK
# ZREMRANGEBYSCORE
# ZUNIONSTORE / ZINTERSTORE
- def zadd(self, key, member, score):
- """
- Add a member to a sorted set, or update its score if it already exists
- """
- self._send('ZADD', key, score, member)
+ def zadd(self, key, *item_tuples, **kwargs):
+ """
+ Add members to a sorted set, or update its score if it already exists
+ @param key : Sorted set key
+ @param item_tuples : Sequence of score, value pairs.
+ e.g. zadd(key, score1, value1, score2, value2)
+ @param member : For backwards compatibility, member name.
+ @param score : For backwards compatibility, score.
+
+ NOTE: if there are only two arguments, the order is interpreted as (value, score)
+ for backwards compatibility reasons.
+ """
+ if not kwargs and len(item_tuples) == 2 and isinstance(item_tuples[0], basestring):
+ self._send('ZADD', key, item_tuples[1], item_tuples[0])
+ elif not kwargs:
+ self._send('ZADD', key, *item_tuples)
+ elif 'member' in kwargs and 'score' in kwargs:
+ score, member = item_tuples
+ self._send('ZADD', key, kwargs['score'], kwargs['member'])
+ else:
+ raise InvalidCommand('Need arguments for ZADD')
return self.getResponse()
- def zrem(self, key, member):
+ def zrem(self, key, *members, **kwargs):
"""
- Remove a member from a sorted set
+ Remove members from a sorted set
+ @param key : Sorted set key
+ @param members : Sequeunce of members to remove
+ @param member : For backwards compatibility - if specified remove one member.
"""
- self._send('ZREM', key, member)
+ if not kwargs:
+ self._send('ZREM', key, *members)
+ elif 'member' in kwargs:
+ self._send('ZREM', key, kwargs['member'])
+ else:
+ raise InvalidCommand('Need arguments for ZREM')
return self.getResponse()
def zremrangebyrank(self, key, start, end):
View
113 txredis/test/test_redis.py
@@ -128,6 +128,21 @@ def test_delete(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_get_object(self):
+ r = self.redis
+ t = self.assertEqual
+ a = yield r.set('obj', 1)
+ ex = 'OK'
+ t(a, ex)
+
+ a = yield r.get_object('obj', idletime=True)
+ self.assertEqual(type(a), int)
+
+ a = yield r.get_object('obj', encoding=True)
+ ex = 'int'
+ t(a, ex)
+
+ @defer.inlineCallbacks
def test_get_type(self):
r = self.redis
t = self.assertEqual
@@ -701,6 +716,23 @@ def test_push(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_push_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('l')
+ yield r.lpush('l', 'a', 'b', 'c', 'd')
+ a = yield r.llen('l')
+ ex = 4
+ t(a, ex)
+
+ yield r.rpush('l', 't', 'u', 'v', 'w')
+ a = yield r.llen('l')
+ ex = 8
+ t(a, ex)
+
+
+ @defer.inlineCallbacks
def test_llen(self):
r = self.redis
t = self.assertEqual
@@ -964,6 +996,18 @@ def test_sadd(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_sadd_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('s')
+ a = yield r.sadd('s', 'a', 'b', 'c', 'd')
+ ex = 4
+ a = yield r.scard('s')
+ ex = 4
+ t(a, ex)
+
+ @defer.inlineCallbacks
def test_sdiff(self):
r = self.redis
t = self.assertEqual
@@ -1032,6 +1076,22 @@ def test_srem(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_srem_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('s')
+ a = yield r.sadd('s', 'a', 'b', 'c', 'd')
+ ex = 4
+ t(a, ex)
+ a = yield r.srem('s', 'a', 'b')
+ ex = 2
+ t(a, ex)
+ a = yield r.scard('s')
+ ex = 2
+ t(a, ex)
+
+ @defer.inlineCallbacks
def test_spop(self):
r = self.redis
t = self.assertEqual
@@ -1364,6 +1424,21 @@ def test_basic(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_hdel_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('d')
+ yield r.hset('d', 'a', 'vala')
+ yield r.hmset('d', {'a' : 'vala', 'b' : 'valb', 'c' : 'valc'})
+ a = yield r.hdel('d', 'a', 'b', 'c')
+ ex = 3
+ t(a, ex)
+ a = yield r.hgetall('d')
+ ex = {}
+ t(a, ex)
+
+ @defer.inlineCallbacks
def test_hincr(self):
r = self.redis
t = self.assertEqual
@@ -1596,6 +1671,44 @@ def test_zremrange(self):
t(a, ex)
@defer.inlineCallbacks
+ def test_add_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('z')
+ yield r.zadd('z', 'a', 1.0)
+ a = yield r.zcard('z')
+ ex = 1
+ t(a, ex)
+
+ # NB. note how for multiple argument it's score then val
+ yield r.zadd('z', 2.0, 'b', 3.0, 'c')
+ a = yield r.zcard('z')
+ ex = 3
+
+ @defer.inlineCallbacks
+ def test_zrem_variable(self):
+ r = self.redis
+ t = self.assertEqual
+
+ yield r.delete('z')
+ yield r.zadd('z', 'a', 1.0)
+ a = yield r.zcard('z')
+ ex = 1
+ t(a, ex)
+
+ # NB. note how for multiple argument it's score then val
+ yield r.zadd('z', 2.0, 'b', 3.0, 'c')
+ a = yield r.zcard('z')
+ ex = 3
+ t(a, ex)
+
+ yield r.zrem('z', 'a', 'b', 'c')
+ a = yield r.zcard('z')
+ ex = 0
+ t(a, ex)
+
+ @defer.inlineCallbacks
def test_zrangebyscore(self):
r = self.redis
t = self.assertEqual

No commit comments for this range

Something went wrong with that request. Please try again.