diff --git a/redis/commands/core.py b/redis/commands/core.py index 4f0accd957..6a21170a72 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -3894,7 +3894,12 @@ def eval(self, script, numkeys, *keys_and_args): """ return self.execute_command("EVAL", script, numkeys, *keys_and_args) - def evalsha(self, sha, numkeys, *keys_and_args): + def _evalsha( + self, command: str, sha: str, numkeys: int, *keys_and_args: list + ) -> str: + return self.execute_command(command, sha, numkeys, *keys_and_args) + + def evalsha(self, sha: str, numkeys: int, *keys_and_args: list) -> str: """ Use the ``sha`` to execute a Lua script already registered via EVAL or SCRIPT LOAD. Specify the ``numkeys`` the script will touch and the @@ -3906,7 +3911,20 @@ def evalsha(self, sha, numkeys, *keys_and_args): For more information check https://redis.io/commands/evalsha """ - return self.execute_command("EVALSHA", sha, numkeys, *keys_and_args) + return self._evalsha("EVALSHA", sha, numkeys, *keys_and_args) + + def evalsha_ro(self, sha: str, numkeys: int, *keys_and_args: list) -> str: + """ + The read-only variant of the EVALSHA command + + Use the ``sha`` to execute a read-only Lua script already registered via EVAL + or SCRIPT LOAD. Specify 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/evalsha_ro + """ + return self._evalsha("EVALSHA_RO", sha, numkeys, *keys_and_args) def script_exists(self, *args): """ diff --git a/tests/test_scripting.py b/tests/test_scripting.py index 9f4f82023f..b216e5377a 100644 --- a/tests/test_scripting.py +++ b/tests/test_scripting.py @@ -1,5 +1,6 @@ import pytest +import redis from redis import exceptions from tests.conftest import skip_if_server_version_lt @@ -66,6 +67,15 @@ def test_evalsha(self, r): # 2 * 3 == 6 assert r.evalsha(sha, 1, "a", 3) == 6 + # @skip_if_server_version_lt("7.0.0") turn on after redis 7 release + def test_evalsha_ro(self, unstable_r): + unstable_r.set("a", "b") + get_sha = unstable_r.script_load("return redis.call('GET', KEYS[1])") + del_sha = unstable_r.script_load("return redis.call('DEL', KEYS[1])") + assert unstable_r.evalsha_ro(get_sha, 1, "a") == b"b" + with pytest.raises(redis.ResponseError): + unstable_r.evalsha_ro(del_sha, 1, "a") + def test_evalsha_script_not_loaded(self, r): r.set("a", 2) sha = r.script_load(multiply_script)