Skip to content

Commit 1448a65

Browse files
committed
Adding support for non-decodable commands
Some commands (i.e DUMP) should never have their response decoded, as they return binaries, not encoded blobs fixes #1254
1 parent d2b2333 commit 1448a65

File tree

4 files changed

+22
-10
lines changed

4 files changed

+22
-10
lines changed

redis/client.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,9 @@
2727
SYM_EMPTY = b''
2828
EMPTY_RESPONSE = 'EMPTY_RESPONSE'
2929

30+
# some responses (ie. dump) are binary, and just meant to never be decoded
31+
NEVER_DECODE = 'NEVER_DECODE'
32+
3033

3134
def timestamp_to_datetime(response):
3235
"Converts a unix timestamp to a Python datetime object"
@@ -1081,7 +1084,10 @@ def execute_command(self, *args, **options):
10811084
def parse_response(self, connection, command_name, **options):
10821085
"Parses a response from the Redis server"
10831086
try:
1084-
response = connection.read_response()
1087+
if NEVER_DECODE in options:
1088+
response = connection.read_response(disable_decoding=True)
1089+
else:
1090+
response = connection.read_response()
10851091
except ResponseError:
10861092
if EMPTY_RESPONSE in options:
10871093
return options[EMPTY_RESPONSE]

redis/commands/core.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -801,7 +801,10 @@ def dump(self, name):
801801
Return a serialized version of the value stored at the specified key.
802802
If key does not exist a nil bulk reply is returned.
803803
"""
804-
return self.execute_command('DUMP', name)
804+
from redis.client import NEVER_DECODE
805+
options = {}
806+
options[NEVER_DECODE] = []
807+
return self.execute_command('DUMP', name, **options)
805808

806809
def exists(self, *names):
807810
"Returns the number of ``names`` that exist"

redis/connection.py

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -314,7 +314,7 @@ def on_disconnect(self):
314314
def can_read(self, timeout):
315315
return self._buffer and self._buffer.can_read(timeout)
316316

317-
def read_response(self):
317+
def read_response(self, disable_decoding=False):
318318
raw = self._buffer.readline()
319319
if not raw:
320320
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
@@ -354,8 +354,9 @@ def read_response(self):
354354
length = int(response)
355355
if length == -1:
356356
return None
357-
response = [self.read_response() for i in range(length)]
358-
if isinstance(response, bytes):
357+
response = [self.read_response(disable_decoding=disable_decoding)
358+
for i in range(length)]
359+
if isinstance(response, bytes) and disable_decoding is False:
359360
response = self.encoder.decode(response)
360361
return response
361362

@@ -449,7 +450,7 @@ def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
449450
if custom_timeout:
450451
sock.settimeout(self._socket_timeout)
451452

452-
def read_response(self):
453+
def read_response(self, disable_decoding=False):
453454
if not self._reader:
454455
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
455456

@@ -742,10 +743,12 @@ def can_read(self, timeout=0):
742743
self.connect()
743744
return self._parser.can_read(timeout)
744745

745-
def read_response(self):
746+
def read_response(self, disable_decoding=False):
746747
"""Read the response from a previously sent command"""
747748
try:
748-
response = self._parser.read_response()
749+
response = self._parser.read_response(
750+
disable_decoding=disable_decoding
751+
)
749752
except socket.timeout:
750753
self.disconnect()
751754
raise TimeoutError("Timeout reading from %s:%s" %

redis/sentinel.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,9 @@ def connect(self):
5151
continue
5252
raise SlaveNotFoundError # Never be here
5353

54-
def read_response(self):
54+
def read_response(self, disable_decoding=False):
5555
try:
56-
return super().read_response()
56+
return super().read_response(disable_decoding=disable_decoding)
5757
except ReadOnlyError:
5858
if self.connection_pool.is_master:
5959
# When talking to a master, a ReadOnlyError when likely

0 commit comments

Comments
 (0)