diff options
author | dvora-h <67596500+dvora-h@users.noreply.github.com> | 2022-02-22 13:11:55 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2022-02-22 13:11:55 +0200 |
commit | fa76ac49a9ea02c204bd4f1644f39d90140cf356 (patch) | |
tree | 0578d5e4748c64824a1f72ed3b64f23c8f57368b /redis | |
parent | f2e34739fccab28a28a066a3ece955eb455b32f9 (diff) | |
download | redis-py-fa76ac49a9ea02c204bd4f1644f39d90140cf356.tar.gz |
Add support for Redis 7 functions (#1998)
* add function support
* linters
* test fcall
* decode reponses for unstable_r
* linters
* fix evalsho_ro test
* fix eval_ro test
* add response callbaks
* linters
Diffstat (limited to 'redis')
-rwxr-xr-x | redis/client.py | 4 | ||||
-rw-r--r-- | redis/commands/core.py | 126 | ||||
-rwxr-xr-x | redis/connection.py | 11 |
3 files changed, 139 insertions, 2 deletions
diff --git a/redis/client.py b/redis/client.py index 22c5dc1..0eade79 100755 --- a/redis/client.py +++ b/redis/client.py @@ -733,6 +733,10 @@ class AbstractRedis: "CONFIG RESETSTAT": bool_ok, "CONFIG SET": bool_ok, "DEBUG OBJECT": parse_debug_object, + "FUNCTION DELETE": bool_ok, + "FUNCTION FLUSH": bool_ok, + "FUNCTION LOAD": bool_ok, + "FUNCTION RESTORE": bool_ok, "GEOHASH": lambda r: list(map(str_if_bytes, r)), "GEOPOS": lambda r: list( map(lambda ll: (float(ll[0]), float(ll[1])) if ll is not None else None, r) diff --git a/redis/commands/core.py b/redis/commands/core.py index 80bc55f..e74550f 100644 --- a/redis/commands/core.py +++ b/redis/commands/core.py @@ -5429,6 +5429,131 @@ class ClusterCommands(CommandsProtocol): return self.execute_command("READONLY", **kwargs) +class FunctionCommands: + """ + Redis Function commands + """ + + def function_load( + self, + engine: str, + library: str, + code: str, + replace: Optional[bool] = False, + description: Optional[str] = None, + ) -> str: + """ + Load a library to Redis. + :param engine: the name of the execution engine for the library + :param library: the unique name of the library + :param code: the source code + :param replace: changes the behavior to replace the library if a library called + ``library`` already exists + :param description: description to the library + + For more information check https://redis.io/commands/function-load + """ + pieces = [engine, library] + if replace: + pieces.append("REPLACE") + if description is not None: + pieces.append(description) + pieces.append(code) + return self.execute_command("FUNCTION LOAD", *pieces) + + def function_delete(self, library: str) -> str: + """ + Delete the library called ``library`` and all its functions. + + For more information check https://redis.io/commands/function-delete + """ + return self.execute_command("FUNCTION DELETE", library) + + def function_flush(self, mode: str = "SYNC") -> str: + """ + Deletes all the libraries. + + For more information check https://redis.io/commands/function-flush + """ + return self.execute_command("FUNCTION FLUSH", mode) + + def function_list( + self, library: Optional[str] = "*", withcode: Optional[bool] = False + ) -> List: + """ + Return information about the functions and libraries. + :param library: pecify a pattern for matching library names + :param withcode: cause the server to include the libraries source + implementation in the reply + """ + args = ["LIBRARYNAME", library] + if withcode: + args.append("WITHCODE") + return self.execute_command("FUNCTION LIST", *args) + + def _fcall( + self, command: str, function, numkeys: int, *keys_and_args: Optional[List] + ) -> str: + return self.execute_command(command, function, numkeys, *keys_and_args) + + def fcall(self, function, numkeys: int, *keys_and_args: Optional[List]) -> str: + """ + Invoke a function. + + For more information check https://redis.io/commands/fcall + """ + return self._fcall("FCALL", function, numkeys, *keys_and_args) + + def fcall_ro(self, function, numkeys: int, *keys_and_args: Optional[List]) -> str: + """ + This is a read-only variant of the FCALL command that cannot + execute commands that modify data. + + For more information check https://redis.io/commands/fcal_ro + """ + return self._fcall("FCALL_RO", function, numkeys, *keys_and_args) + + def function_dump(self) -> str: + """ + Return the serialized payload of loaded libraries. + + For more information check https://redis.io/commands/function-dump + """ + from redis.client import NEVER_DECODE + + options = {} + options[NEVER_DECODE] = [] + + return self.execute_command("FUNCTION DUMP", **options) + + def function_restore(self, payload: str, policy: Optional[str] = "APPEND") -> str: + """ + Restore libraries from the serialized ``payload``. + You can use the optional policy argument to provide a policy + for handling existing libraries. + + For more information check https://redis.io/commands/function-restore + """ + return self.execute_command("FUNCTION RESTORE", payload, policy) + + def function_kill(self) -> str: + """ + Kill a function that is currently executing. + + For more information check https://redis.io/commands/function-kill + """ + return self.execute_command("FUNCTION KILL") + + def function_stats(self) -> list: + """ + Return information about the function that's currently running + and information about the available execution engines. + + For more information check https://redis.io/commands/function-stats + """ + return self.execute_command("FUNCTION STATS") + + AsyncClusterCommands = ClusterCommands @@ -5474,6 +5599,7 @@ class CoreCommands( ModuleCommands, PubSubCommands, ScriptCommands, + FunctionCommands, ): """ A class containing all of the implemented redis commands. This class is diff --git a/redis/connection.py b/redis/connection.py index 891695d..189cecb 100755 --- a/redis/connection.py +++ b/redis/connection.py @@ -463,10 +463,17 @@ class HiredisParser(BaseParser): self._next_response = False return response - response = self._reader.gets() + if disable_decoding: + response = self._reader.gets(False) + else: + response = self._reader.gets() + while response is False: self.read_from_socket() - response = self._reader.gets() + if disable_decoding: + response = self._reader.gets(False) + else: + response = self._reader.gets() # if an older version of hiredis is installed, we need to attempt # to convert ResponseErrors to their appropriate types. if not HIREDIS_SUPPORTS_CALLABLE_ERRORS: |