diff options
-rwxr-xr-x | redis/client.py | 8 | ||||
-rw-r--r-- | redis/commands/core.py | 5 | ||||
-rwxr-xr-x | redis/connection.py | 15 | ||||
-rw-r--r-- | redis/sentinel.py | 4 |
4 files changed, 22 insertions, 10 deletions
diff --git a/redis/client.py b/redis/client.py index dc6693d..b218c1d 100755 --- a/redis/client.py +++ b/redis/client.py @@ -27,6 +27,9 @@ from redis.utils import safe_str, str_if_bytes SYM_EMPTY = b'' EMPTY_RESPONSE = 'EMPTY_RESPONSE' +# some responses (ie. dump) are binary, and just meant to never be decoded +NEVER_DECODE = 'NEVER_DECODE' + def timestamp_to_datetime(response): "Converts a unix timestamp to a Python datetime object" @@ -1081,7 +1084,10 @@ class Redis(RedisModuleCommands, CoreCommands, SentinelCommands, object): def parse_response(self, connection, command_name, **options): "Parses a response from the Redis server" try: - response = connection.read_response() + if NEVER_DECODE in options: + response = connection.read_response(disable_decoding=True) + else: + response = connection.read_response() except ResponseError: if EMPTY_RESPONSE in options: return options[EMPTY_RESPONSE] diff --git a/redis/commands/core.py b/redis/commands/core.py index 516e7d9..09fcc5d 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -801,7 +801,10 @@ class CoreCommands: Return a serialized version of the value stored at the specified key. If key does not exist a nil bulk reply is returned. """ - return self.execute_command('DUMP', name) + from redis.client import NEVER_DECODE + options = {} + options[NEVER_DECODE] = [] + return self.execute_command('DUMP', name, **options) def exists(self, *names): "Returns the number of ``names`` that exist" diff --git a/redis/connection.py b/redis/connection.py index e01742d..3de87ae 100755 --- a/redis/connection.py +++ b/redis/connection.py @@ -314,7 +314,7 @@ class PythonParser(BaseParser): def can_read(self, timeout): return self._buffer and self._buffer.can_read(timeout) - def read_response(self): + def read_response(self, disable_decoding=False): raw = self._buffer.readline() if not raw: raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) @@ -354,8 +354,9 @@ class PythonParser(BaseParser): length = int(response) if length == -1: return None - response = [self.read_response() for i in range(length)] - if isinstance(response, bytes): + response = [self.read_response(disable_decoding=disable_decoding) + for i in range(length)] + if isinstance(response, bytes) and disable_decoding is False: response = self.encoder.decode(response) return response @@ -449,7 +450,7 @@ class HiredisParser(BaseParser): if custom_timeout: sock.settimeout(self._socket_timeout) - def read_response(self): + def read_response(self, disable_decoding=False): if not self._reader: raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR) @@ -742,10 +743,12 @@ class Connection: self.connect() return self._parser.can_read(timeout) - def read_response(self): + def read_response(self, disable_decoding=False): """Read the response from a previously sent command""" try: - response = self._parser.read_response() + response = self._parser.read_response( + disable_decoding=disable_decoding + ) except socket.timeout: self.disconnect() raise TimeoutError("Timeout reading from %s:%s" % diff --git a/redis/sentinel.py b/redis/sentinel.py index 17dd75b..3efd58f 100644 --- a/redis/sentinel.py +++ b/redis/sentinel.py @@ -51,9 +51,9 @@ class SentinelManagedConnection(Connection): continue raise SlaveNotFoundError # Never be here - def read_response(self): + def read_response(self, disable_decoding=False): try: - return super().read_response() + return super().read_response(disable_decoding=disable_decoding) except ReadOnlyError: if self.connection_pool.is_master: # When talking to a master, a ReadOnlyError when likely |