Skip to content

Commit d7b5610

Browse files
authored
Adding support for non-decodable commands (#1731)
1 parent 8991370 commit d7b5610

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"
@@ -1106,7 +1109,10 @@ def execute_command(self, *args, **options):
11061109
def parse_response(self, connection, command_name, **options):
11071110
"Parses a response from the Redis server"
11081111
try:
1109-
response = connection.read_response()
1112+
if NEVER_DECODE in options:
1113+
response = connection.read_response(disable_decoding=True)
1114+
else:
1115+
response = connection.read_response()
11101116
except ResponseError:
11111117
if EMPTY_RESPONSE in options:
11121118
return options[EMPTY_RESPONSE]

redis/commands/core.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1008,7 +1008,10 @@ def dump(self, name):
10081008
10091009
For more information check https://redis.io/commands/dump
10101010
"""
1011-
return self.execute_command('DUMP', name)
1011+
from redis.client import NEVER_DECODE
1012+
options = {}
1013+
options[NEVER_DECODE] = []
1014+
return self.execute_command('DUMP', name, **options)
10121015

10131016
def exists(self, *names):
10141017
"""

redis/connection.py

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

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

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

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

@@ -758,10 +759,12 @@ def can_read(self, timeout=0):
758759
self.connect()
759760
return self._parser.can_read(timeout)
760761

761-
def read_response(self):
762+
def read_response(self, disable_decoding=False):
762763
"""Read the response from a previously sent command"""
763764
try:
764-
response = self._parser.read_response()
765+
response = self._parser.read_response(
766+
disable_decoding=disable_decoding
767+
)
765768
except socket.timeout:
766769
self.disconnect()
767770
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)