diff --git a/redis/client.py b/redis/client.py index 87c79913d3..2afdca9064 100755 --- a/redis/client.py +++ b/redis/client.py @@ -557,6 +557,10 @@ def parse_command(response, **options): cmd_dict["first_key_pos"] = command[3] cmd_dict["last_key_pos"] = command[4] cmd_dict["step_count"] = command[5] + if len(command) > 7: + cmd_dict["tips"] = command[7] + cmd_dict["key_specifications"] = command[8] + cmd_dict["subcommands"] = command[9] commands[cmd_name] = cmd_dict return commands diff --git a/redis/cluster.py b/redis/cluster.py index bf7ac2049b..12796c635f 100644 --- a/redis/cluster.py +++ b/redis/cluster.py @@ -223,6 +223,7 @@ class RedisCluster(RedisClusterCommands): [ "ACL CAT", "ACL DELUSER", + "ACL DRYRUN", "ACL GENPASS", "ACL GETUSER", "ACL HELP", diff --git a/redis/commands/parser.py b/redis/commands/parser.py index 89292ab2d3..11162127fc 100644 --- a/redis/commands/parser.py +++ b/redis/commands/parser.py @@ -26,6 +26,21 @@ def initialize(self, r): commands[cmd.lower()] = commands.pop(cmd) self.commands = commands + def parse_subcommand(self, command, **options): + cmd_dict = {} + cmd_name = str_if_bytes(command[0]) + cmd_dict["name"] = cmd_name + cmd_dict["arity"] = int(command[1]) + cmd_dict["flags"] = [str_if_bytes(flag) for flag in command[2]] + cmd_dict["first_key_pos"] = command[3] + cmd_dict["last_key_pos"] = command[4] + cmd_dict["step_count"] = command[5] + if len(command) > 7: + cmd_dict["tips"] = command[7] + cmd_dict["key_specifications"] = command[8] + cmd_dict["subcommands"] = command[9] + return cmd_dict + # As soon as this PR is merged into Redis, we should reimplement # our logic to use COMMAND INFO changes to determine the key positions # https://github.com/redis/redis/pull/8324 @@ -73,8 +88,17 @@ def get_keys(self, redis_conn, *args): and command["first_key_pos"] == 0 and command["last_key_pos"] == 0 ): + is_subcmd = False + if "subcommands" in command: + subcmd_name = f"{cmd_name}|{args[1].lower()}" + for subcmd in command["subcommands"]: + if str_if_bytes(subcmd[0]) == subcmd_name: + command = self.parse_subcommand(subcmd) + is_subcmd = True + # The command doesn't have keys in it - return None + if not is_subcmd: + return None last_key_pos = command["last_key_pos"] if last_key_pos < 0: last_key_pos = len(args) - abs(last_key_pos) diff --git a/tests/test_cluster.py b/tests/test_cluster.py index 3794c31891..ced9062275 100644 --- a/tests/test_cluster.py +++ b/tests/test_cluster.py @@ -1098,7 +1098,6 @@ def test_cluster_links(self, r): links_to = sum(x.count("to") for x in res) links_for = sum(x.count("from") for x in res) assert links_to == links_for - print(res) for i in range(0, len(res) - 1, 2): assert res[i][3] == res[i + 1][3] diff --git a/tests/test_commands.py b/tests/test_commands.py index b7287b4fea..075f46ec14 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -1164,7 +1164,7 @@ def test_expire_option_xx(self, r): r.set("key", "val") assert r.expire("key", 100, xx=True) == 0 assert r.expire("key", 100) - assert r.expire("key", 500, nx=True) == 1 + assert r.expire("key", 500, xx=True) == 1 @skip_if_server_version_lt("7.0.0") def test_expire_option_gt(self, r): @@ -3012,6 +3012,7 @@ def test_sort_all_options(self, r): assert r.lrange("sorted", 0, 10) == [b"vodka", b"milk", b"gin", b"apple juice"] @skip_if_server_version_lt("7.0.0") + @pytest.mark.onlynoncluster def test_sort_ro(self, r): r["score:1"] = 8 r["score:2"] = 3