andymccurdy/redis-py — pull request #275 by flupke (2012-08-30 16:52:26+00:00)
Title: Add an option to avoid releasing PubSub connection

I ran into a problem trying to reuse a single PubSub object for many channels:
```python
client = Redis()
pubsub = client.pubsub()
pubsub.subscribe('foo')
# [...]
pubsub.unsubscribe('foo')
pubsub.subscribe('bar')
for message in pubsub.listen():
pass
```

The last listen() fails, because the PubSub connection is None at this time:
```
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/gevent/greenlet.py", line 328, in run
result = self._run(*self.args, **self.kwargs)
# [...]
File "/home/flupke/src/ext/redis-py/redis/client.py", line 1496, in listen
r = self.parse_response()
File "/home/flupke/src/ext/redis-py/redis/client.py", line 1440, in parse_response
response = self.connection.read_response()
AttributeError: 'NoneType' object has no attribute 'read_response'
```

This is because I wasn't parsing responses, and PubSub recycles the connection when it catches a response indicating there are no more channels subscriptions. The fix is to parse responses after each pub/sub call:
```python
client = Redis()
pubsub = client.pubsub()
pubsub.subscribe('foo')
pubsub.parse_response()
# [...]
pubsub.unsubscribe('foo')
pubsub.parse_response()
pubsub.subscribe('bar')
pubsub.parse_response()
for message in pubsub.listen():
pass
```

This is a bit cumbersome, but the real problem is that an unnecessary Redis disconnect/connect cycle is made. The patch adds a release_connection option to StrictRedis.pubsub() and PubSub's constructor to avoid this behavior.