From 0645a9388e38b3b795ec4972fb4f86fba283b6e4 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 12:05:36 +0200 Subject: [PATCH 01/10] add sort_ro --- redis/commands/core.py | 34 ++++++++++++++++++++++++++++++++++ tests/test_commands.py | 10 ++++++++++ 2 files changed, 44 insertions(+) diff --git a/redis/commands/core.py b/redis/commands/core.py index 4f0accd957..d4626d5076 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -2,6 +2,7 @@ import hashlib import time import warnings +from typing import List, Optional from redis.exceptions import ConnectionError, DataError, NoScriptError, RedisError @@ -2184,6 +2185,39 @@ def sort( options = {"groups": len(get) if groups else None} return self.execute_command("SORT", *pieces, **options) + def sort_ro( + self, + key: str, + start: Optional[int] = None, + num: Optional[int] = None, + by: Optional[str] = None, + get: Optional[List[str]] = None, + desc: bool = False, + alpha: bool = False, + ) -> list: + """ + Returns the elements contained in the list, set or sorted set at key. + (read-only variant of the SORT command) + + ``start`` and ``num`` allow for paging through the sorted data + + ``by`` allows using an external key to weight and sort the items. + Use an "*" to indicate where in the key the item value is located + + ``get`` allows for returning items from external keys rather than the + sorted data itself. Use an "*" to indicate where in the key + the item value is located + + ``desc`` allows for reversing the sort + + ``alpha`` allows for sorting lexicographically rather than numerically + + For more information check https://redis.io/commands/sort_ro + """ + return self.sort( + key, start=start, num=num, by=by, get=get, desc=desc, alpha=alpha + ) + class ScanCommands: """ diff --git a/tests/test_commands.py b/tests/test_commands.py index b28b63ea6e..99ed26c6f3 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -2639,6 +2639,16 @@ def test_sort_all_options(self, r): assert num == 4 assert r.lrange("sorted", 0, 10) == [b"vodka", b"milk", b"gin", b"apple juice"] + # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release + def test_sort_ro(self, unstable_r): + unstable_r["score:1"] = 8 + unstable_r["score:2"] = 3 + unstable_r["score:3"] = 5 + unstable_r.rpush("a", "3", "2", "1") + assert unstable_r.sort_ro("a", by="score:*") == [b"2", b"3", b"1"] + unstable_r.rpush("b", "2", "3", "1") + assert unstable_r.sort_ro("b", desc=True) == [b"3", b"2", b"1"] + def test_sort_issue_924(self, r): # Tests for issue https://github.com/andymccurdy/redis-py/issues/924 r.execute_command("SADD", "issue#924", 1) From 86acf179ab3f8306c83a712d9df74600a7c8bc1d Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 13:06:57 +0200 Subject: [PATCH 02/10] mark test as onlynon cluster --- tests/test_commands.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_commands.py b/tests/test_commands.py index 99ed26c6f3..3f2be1f3c7 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -2639,6 +2639,7 @@ def test_sort_all_options(self, r): assert num == 4 assert r.lrange("sorted", 0, 10) == [b"vodka", b"milk", b"gin", b"apple juice"] + @pytest.mark.onlynoncluster # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release def test_sort_ro(self, unstable_r): unstable_r["score:1"] = 8 From 47d2e74a01ad0607b4fcc8adfae0d39c8ede7be8 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 13:22:41 +0200 Subject: [PATCH 03/10] delete mark test as onlynoncluster --- tests/test_commands.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_commands.py b/tests/test_commands.py index 3f2be1f3c7..99ed26c6f3 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -2639,7 +2639,6 @@ def test_sort_all_options(self, r): assert num == 4 assert r.lrange("sorted", 0, 10) == [b"vodka", b"milk", b"gin", b"apple juice"] - @pytest.mark.onlynoncluster # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release def test_sort_ro(self, unstable_r): unstable_r["score:1"] = 8 From a7cf4492119e37d3f4a782f28abc98f7bd81235f Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 15:06:20 +0200 Subject: [PATCH 04/10] add eval_ro --- redis/commands/core.py | 12 ++++++++++++ tests/test_scripting.py | 8 ++++++++ 2 files changed, 20 insertions(+) diff --git a/redis/commands/core.py b/redis/commands/core.py index d4626d5076..e66112a4c3 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3928,6 +3928,18 @@ def eval(self, script, numkeys, *keys_and_args): """ return self.execute_command("EVAL", script, numkeys, *keys_and_args) + def eval_ro(self, script, numkeys, *keys_and_args): + """ + The read-only variant of the EVAL command + + Execute the read-only Lue ``script`` specifying the ``numkeys`` the script + will touch and the key names and argument values in ``keys_and_args``. + Returns the result of the script. + + For more information check https://redis.io/commands/eval_ro + """ + return self.execute_command("EVAL_RO", script, numkeys, *keys_and_args) + def evalsha(self, sha, numkeys, *keys_and_args): """ Use the ``sha`` to execute a Lua script already registered via EVAL diff --git a/tests/test_scripting.py b/tests/test_scripting.py index 9f4f82023f..1c0b77d48d 100644 --- a/tests/test_scripting.py +++ b/tests/test_scripting.py @@ -1,6 +1,7 @@ import pytest from redis import exceptions +import redis from tests.conftest import skip_if_server_version_lt multiply_script = """ @@ -31,6 +32,13 @@ def test_eval(self, r): # 2 * 3 == 6 assert r.eval(multiply_script, 1, "a", 3) == 6 + # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release + def test_eval_ro(self, unstable_r): + unstable_r.set("a", "b") + assert unstable_r.eval_ro("return redis.call('GET', KEYS[1])", 1, "a") == b'b' + with pytest.raises(redis.ResponseError): + unstable_r.eval_ro("return redis.call('DEL', KEYS[1])", 1, "a") + @skip_if_server_version_lt("6.2.0") def test_script_flush_620(self, r): r.set("a", 2) From 8724607947534d9de13a87a0b3d461d56cbcae48 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 15:12:44 +0200 Subject: [PATCH 05/10] fix linters --- tests/test_scripting.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_scripting.py b/tests/test_scripting.py index 1c0b77d48d..b0d76c7335 100644 --- a/tests/test_scripting.py +++ b/tests/test_scripting.py @@ -1,7 +1,7 @@ import pytest -from redis import exceptions import redis +from redis import exceptions from tests.conftest import skip_if_server_version_lt multiply_script = """ @@ -35,7 +35,7 @@ def test_eval(self, r): # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release def test_eval_ro(self, unstable_r): unstable_r.set("a", "b") - assert unstable_r.eval_ro("return redis.call('GET', KEYS[1])", 1, "a") == b'b' + assert unstable_r.eval_ro("return redis.call('GET', KEYS[1])", 1, "a") == b"b" with pytest.raises(redis.ResponseError): unstable_r.eval_ro("return redis.call('DEL', KEYS[1])", 1, "a") From a694dfbdb500b69facc730bc351af591b43e5a12 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 5 Jan 2022 16:40:05 +0200 Subject: [PATCH 06/10] delete sort_ro --- redis/commands/core.py | 34 ---------------------------------- tests/test_commands.py | 10 ---------- 2 files changed, 44 deletions(-) diff --git a/redis/commands/core.py b/redis/commands/core.py index e66112a4c3..46c9d04d1b 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -2,7 +2,6 @@ import hashlib import time import warnings -from typing import List, Optional from redis.exceptions import ConnectionError, DataError, NoScriptError, RedisError @@ -2185,39 +2184,6 @@ def sort( options = {"groups": len(get) if groups else None} return self.execute_command("SORT", *pieces, **options) - def sort_ro( - self, - key: str, - start: Optional[int] = None, - num: Optional[int] = None, - by: Optional[str] = None, - get: Optional[List[str]] = None, - desc: bool = False, - alpha: bool = False, - ) -> list: - """ - Returns the elements contained in the list, set or sorted set at key. - (read-only variant of the SORT command) - - ``start`` and ``num`` allow for paging through the sorted data - - ``by`` allows using an external key to weight and sort the items. - Use an "*" to indicate where in the key the item value is located - - ``get`` allows for returning items from external keys rather than the - sorted data itself. Use an "*" to indicate where in the key - the item value is located - - ``desc`` allows for reversing the sort - - ``alpha`` allows for sorting lexicographically rather than numerically - - For more information check https://redis.io/commands/sort_ro - """ - return self.sort( - key, start=start, num=num, by=by, get=get, desc=desc, alpha=alpha - ) - class ScanCommands: """ diff --git a/tests/test_commands.py b/tests/test_commands.py index 99ed26c6f3..b28b63ea6e 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -2639,16 +2639,6 @@ def test_sort_all_options(self, r): assert num == 4 assert r.lrange("sorted", 0, 10) == [b"vodka", b"milk", b"gin", b"apple juice"] - # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release - def test_sort_ro(self, unstable_r): - unstable_r["score:1"] = 8 - unstable_r["score:2"] = 3 - unstable_r["score:3"] = 5 - unstable_r.rpush("a", "3", "2", "1") - assert unstable_r.sort_ro("a", by="score:*") == [b"2", b"3", b"1"] - unstable_r.rpush("b", "2", "3", "1") - assert unstable_r.sort_ro("b", desc=True) == [b"3", b"2", b"1"] - def test_sort_issue_924(self, r): # Tests for issue https://github.com/andymccurdy/redis-py/issues/924 r.execute_command("SADD", "issue#924", 1) From 112ad7d622d44606cee6d4dfb97a93be458fb410 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Thu, 13 Jan 2022 14:15:11 +0200 Subject: [PATCH 07/10] fix pr comment --- redis/commands/core.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/redis/commands/core.py b/redis/commands/core.py index 46c9d04d1b..f32486dcef 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3881,6 +3881,9 @@ class ScriptCommands: https://redis.com/ebook/part-3-next-steps/chapter-11-scripting-redis-with-lua/ """ + def _eval(self, command, script, numkeys, *keys_and_args): + return self.execute_command(command, script, numkeys, *keys_and_args) + def eval(self, script, numkeys, *keys_and_args): """ Execute the Lua ``script``, specifying the ``numkeys`` the script @@ -3892,7 +3895,7 @@ def eval(self, script, numkeys, *keys_and_args): For more information check https://redis.io/commands/eval """ - return self.execute_command("EVAL", script, numkeys, *keys_and_args) + return self._eval("EVAL", script, numkeys, *keys_and_args) def eval_ro(self, script, numkeys, *keys_and_args): """ @@ -3904,7 +3907,7 @@ def eval_ro(self, script, numkeys, *keys_and_args): For more information check https://redis.io/commands/eval_ro """ - return self.execute_command("EVAL_RO", script, numkeys, *keys_and_args) + return self._eval("EVAL_RO", script, numkeys, *keys_and_args) def evalsha(self, sha, numkeys, *keys_and_args): """ From 28f12d2d3fc01c3c2d39633d3f37bec47557419b Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 19 Jan 2022 03:26:02 +0200 Subject: [PATCH 08/10] add type hints --- redis/commands/core.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/redis/commands/core.py b/redis/commands/core.py index f32486dcef..adf127bdb0 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3897,7 +3897,7 @@ def eval(self, script, numkeys, *keys_and_args): """ return self._eval("EVAL", script, numkeys, *keys_and_args) - def eval_ro(self, script, numkeys, *keys_and_args): + def eval_ro(self, script: str, numkeys: int, *keys_and_args: list) -> str: """ The read-only variant of the EVAL command From a99f7d8e45ed5eac1eaf8a7663e08c3b1c4176a9 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 19 Jan 2022 09:46:04 +0200 Subject: [PATCH 09/10] add type hints --- redis/commands/core.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/redis/commands/core.py b/redis/commands/core.py index adf127bdb0..8bff6eb912 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3881,10 +3881,16 @@ class ScriptCommands: https://redis.com/ebook/part-3-next-steps/chapter-11-scripting-redis-with-lua/ """ - def _eval(self, command, script, numkeys, *keys_and_args): + def _eval( + self, + command: str, + script: str, + numkeys: int, + *keys_and_args: list + ) -> str: return self.execute_command(command, script, numkeys, *keys_and_args) - def eval(self, script, numkeys, *keys_and_args): + def eval(self, script: str, numkeys: int, *keys_and_args: list) -> str: """ Execute the Lua ``script``, specifying the ``numkeys`` the script will touch and the key names and argument values in ``keys_and_args``. From 48d626b0f4fa31f59f6bc0b5f413daa4209af406 Mon Sep 17 00:00:00 2001 From: dvora-h Date: Wed, 19 Jan 2022 09:58:55 +0200 Subject: [PATCH 10/10] linters --- redis/commands/core.py | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/redis/commands/core.py b/redis/commands/core.py index 8bff6eb912..49e0590def 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3882,11 +3882,7 @@ class ScriptCommands: """ def _eval( - self, - command: str, - script: str, - numkeys: int, - *keys_and_args: list + self, command: str, script: str, numkeys: int, *keys_and_args: list ) -> str: return self.execute_command(command, script, numkeys, *keys_and_args)