summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndy McCurdy <andy@andymccurdy.com>2011-06-01 01:08:10 -0700
committerAndy McCurdy <andy@andymccurdy.com>2011-06-01 01:08:10 -0700
commit2c4b66d40d34f71742e9a0bf5c4721eee66fc6a1 (patch)
tree2a0b27dc0fe740d2c19d17af36008d4538498fbd
parent47a4a7e339ea9c4243ea14303d7234f0de13f959 (diff)
downloadredis-py-2c4b66d40d34f71742e9a0bf5c4721eee66fc6a1.tar.gz
pipelines need the response_callback love, too. grammar fixes in docs
-rw-r--r--README.md47
-rw-r--r--redis/client.py10
-rw-r--r--tests/server_commands.py15
3 files changed, 46 insertions, 26 deletions
diff --git a/README.md b/README.md
index b4ee819..1ebfa92 100644
--- a/README.md
+++ b/README.md
@@ -43,8 +43,8 @@ are managed.
ConnectionPools manage a set of Connection instances. redis-py ships with two
types of Connections. The default, Connection, is a normal TCP socket based
-connection. UnixDomainSocketConnection allows for clients running on the same
-device to connect via a unix domain socket. To use a
+connection. The UnixDomainSocketConnection allows for clients running on the
+same device as the server to connect via a unix domain socket. To use a
UnixDomainSocketConnection connection, simply pass the class to the
connection_class argument of either the Redis or ConnectionPool class. You must
also specify the path argument, which is a string to the unix domain socket
@@ -60,15 +60,16 @@ useful if you want to control the socket behavior within an async framework.
### Parsers
Parser classes provide a way to control how responses from the Redis server
-are parsed. redis-py ships with two parse classes, the PythonParse and the
+are parsed. redis-py ships with two parser classes, the PythonParser and the
HiredisParser. By default, redis-py will attempt to use the HiredisParser if
you have the hiredis module installed and will fallback to the PythonParser
otherwise.
Hiredis is a C library maintained by the core Redis team. Pieter Noordhuis was
kind enough to create Python bindings. Using Hiredis can provide up to a
-10x speed improvement. The performance increase is most noticeable when
-retrieving many pieces of data, such as from a ZRANGE or HGETALL operation.
+10x speed improvement in parsing responses from the Redis server. The
+performance increase is most noticeable when retrieving many pieces of data,
+such as from LRANGE or SMEMBERS operations.
Hiredis is available on Pypi, and can be installed via pip or easy_install
just like redis-py.
@@ -89,14 +90,14 @@ Custom callbacks can be added on a per-instance basis using the
set_response_callback method. This method accepts two arguments: a command
name and the callback. Callbacks added in this manner are only valid on the
instance the callback is added to. If you want to define or override a callback
-globally, then you should look into making a subclass and added your callback
-to the REDIS_CALLBACKS class dictionary.
+globally, you should make a subclass of the Redis client and add your callback
+to its REDIS_CALLBACKS class dictionary.
Response callbacks take at least one parameter: the response from the Redis
server. Keyword arguments may also be accepted in order to further control
-how to interpret the response. The keyword arguments are specified during the
+how to interpret the response. These keyword arguments are specified during the
command's call to execute_command. The ZRANGE implementation demonstrates the
-use of response callback keyword arguments using the "withscores" argument.
+use of response callback keyword arguments with its "withscores" argument.
## Thread Safety
@@ -106,19 +107,15 @@ command execution, and returned to the pool directly after. Command execution
never modifies state on the client instance.
However, there is one caveat: the Redis SELECT command. The SELECT command
-allows you to switch to a separate database on the same Redis server. That
-database remains selected until another is selected. This creates a proble in
-that connections could be returned to the pool that are now set to a different
-database.
+allows you to switch the database currently in use by the connection. That
+database remains selected until another is selected or until the connection is
+closed. This creates an issue in that connections could be returned to the pool
+that are connected to a different database.
As a result, redis-py does not implement the SELECT command on client instances.
-If you use multiple Redis databases, you should create a separate client
-instance (and possible a separate connection pool) to each database.
-
-## Versioning scheme
-
-redis-py is versioned after Redis. So, for example, redis-py 2.0.0 should
-support all the commands available in Redis 2.0.0.
+If you use multiple Redis databases within the same application, you should
+create a separate client instance (and possibly a separate connection pool) for
+each database.
## API Reference
@@ -131,20 +128,24 @@ arguments as the official spec. There are a few exceptions noted here:
* ZADD: Redis specifies the 'score' argument before 'value'. These were swapped
accidentally when being implemented and not discovered until after people
were already using it. As of Redis 2.4, ZADD will start supporting variable
- arguments. redis-py implements these as python keyword arguments, where the
+ arguments. redis-py implements these as python keyword arguments where the
name is the 'value' and the value is the 'score'.
* DEL: 'del' is a reserved keyword in the Python syntax. Therefore redis-py
uses 'delete' instead.
-* CONFIG GET|SET: These are implemented separately config_get or config_set.
+* CONFIG GET|SET: These are implemented separately as config_get or config_set.
* MULTI/EXEC: These are implemented as part of the Pipeline class. Calling
the pipeline method and specifying use_transaction=True will cause the
- pipline to be wrapped with the MULTI and EXEC statements when it is executed.
+ pipeline to be wrapped with the MULTI and EXEC statements when it is executed.
* SUBSCRIBE/LISTEN: Similar to pipelines, PubSub is implemented as a separate
class as it places the underlying connection in a state where it can't
execute non-pubsub commands. Calling the pubsub method from the Redis client
will return a PubSub instance where you can subscribe to channels and listen
for messages. You can call PUBLISH from both classes.
+## Versioning scheme
+
+redis-py is versioned after Redis. For example, redis-py 2.0.0 should
+support all the commands available in Redis 2.0.0.
Author
------
diff --git a/redis/client.py b/redis/client.py
index c14499c..14dde9e 100644
--- a/redis/client.py
+++ b/redis/client.py
@@ -196,7 +196,11 @@ class Redis(object):
atomic, pipelines are useful for reducing the back-and-forth overhead
between the client and server.
"""
- return Pipeline(self.connection_pool, transaction, shard_hint)
+ return Pipeline(
+ self.connection_pool,
+ self.response_callbacks,
+ transaction,
+ shard_hint)
def lock(self, name, timeout=None, sleep=0.1):
"""
@@ -1170,8 +1174,10 @@ class Pipeline(Redis):
ResponseError exceptions, such as those raised when issuing a command
on a key of a different datatype.
"""
- def __init__(self, connection_pool, transaction, shard_hint):
+ def __init__(self, connection_pool, response_callbacks, transaction,
+ shard_hint):
self.connection_pool = connection_pool
+ self.response_callbacks = response_callbacks
self.transaction = transaction
self.shard_hint = shard_hint
self.reset()
diff --git a/tests/server_commands.py b/tests/server_commands.py
index babb98e..9d82eac 100644
--- a/tests/server_commands.py
+++ b/tests/server_commands.py
@@ -18,6 +18,17 @@ class ServerCommandsTestCase(unittest.TestCase):
self.client.flushdb()
self.client.connection_pool.disconnect()
+ def test_response_callbacks(self):
+ self.assertEquals(
+ self.client.response_callbacks,
+ redis.Redis.RESPONSE_CALLBACKS)
+ self.assertNotEquals(
+ id(self.client.response_callbacks),
+ id(redis.Redis.RESPONSE_CALLBACKS))
+ self.client.set_response_callback('GET', lambda x: 'static')
+ self.client.set('a', 'foo')
+ self.assertEquals(self.client.get('a'), 'static')
+
# GENERAL SERVER COMMANDS
def test_dbsize(self):
self.client['a'] = 'foo'
@@ -35,7 +46,9 @@ class ServerCommandsTestCase(unittest.TestCase):
self.assert_(self.client.set('unicode_string', unicode_string))
self.assertEquals(self.client.get('byte_string'), byte_string)
self.assertEquals(self.client.get('integer'), str(integer))
- self.assertEquals(self.client.get('unicode_string').decode('utf-8'), unicode_string)
+ self.assertEquals(
+ self.client.get('unicode_string').decode('utf-8'),
+ unicode_string)
def test_getitem_and_setitem(self):
self.client['a'] = 'bar'