Repository: redis/redis-py

Issue:
slowlog_get() raises TypeError when decode_responses=True
**Version**: redis-py 3.3.11 and AWS ElastiCache Redis 5.0.5 (Cluster mode off, 1 shard, 2 nodes)

**Platform**: Python 3.7.5 on macOS Catalina 10.15.1

**Description**: Calling slowlog_get() on a redis.Redis client instance with decode_responses=True raises a TypeError: 

```
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "/Users/.../lib/python3.7/site-packages/redis/client.py", line 1192, in slowlog_get
    return self.execute_command(*args)
  File "/Users/.../lib/python3.7/site-packages/redis/client.py", line 839, in execute_command
    return self.parse_response(conn, command_name, **options)
  File "/Users/.../lib/python3.7/site-packages/redis/client.py", line 859, in parse_response
    return self.response_callbacks[command_name](response, **options)
  File "/Users/.../lib/python3.7/site-packages/redis/client.py", line 397, in parse_slowlog_get
    } for item in response]
  File "/Users/.../lib/python3.7/site-packages/redis/client.py", line 397, in <listcomp>
    } for item in response]
TypeError: sequence item 0: expected a bytes-like object, str found
```

The command executes just fine when decode_responses=False (default).

As a preliminary work-around, I replaced the type of whitespace used on [line 396 in parse_slowlog_get() of client.py](https://github.com/andymccurdy/redis-py/blob/29f4aa43aec50ae0e28df4d3fadfcb17cebe2a2f/redis/client.py#L396) (bytes -> str):
`'command': ' '.join(item[3])` (remove `b`)

Of course, this no longer handles the default case (decode_responses=False).

There are various ways to address this issue, including:
1. Somehow pass the value of decode_responses and substitute b' ' by ' ' where appropriate (is this relevant in other places, too?)
2. Determine type of list members (bytes vs. str) and use appropriate whitespace type
3. Optimistically keep the current implementation, but wrap it in a try-except block and retry with alternative implementation on exception

I am leaning towards option 1 and would be willing to create a PR, if it helps. Since I'm a noob here, it would help if you could point me to a similar issue for guidance. Thanks!


Discussion:

Resolving patch:
diff --git a/redis/client.py b/redis/client.py
--- a/redis/client.py
+++ b/redis/client.py
@@ -389,11 +389,12 @@ def parse_zscan(response, **options):
 
 
 def parse_slowlog_get(response, **options):
+    space = ' ' if options.get('decode_responses', False) else b' '
     return [{
         'id': item[0],
         'start_time': int(item[1]),
         'duration': int(item[2]),
-        'command': b' '.join(item[3])
+        'command': space.join(item[3])
     } for item in response]
 
 
@@ -1189,7 +1190,9 @@ def slowlog_get(self, num=None):
         args = ['SLOWLOG GET']
         if num is not None:
             args.append(num)
-        return self.execute_command(*args)
+        decode_responses = self.connection_pool.connection_kwargs.get(
+            'decode_responses', False)
+        return self.execute_command(*args, decode_responses=decode_responses)
 
     def slowlog_len(self):
         "Get the number of items in the slowlog"


Test patch: