From 290b7af9fbe9f6c7d22479325d6d2a38f991d735 Mon Sep 17 00:00:00 2001 From: Shoham Elias Date: Mon, 17 Jun 2024 12:45:08 +0000 Subject: [PATCH 1/6] Python: Added FUNCTION LOAD command --- CHANGELOG.md | 1 + .../glide/async_commands/cluster_commands.py | 34 +++++++ .../async_commands/standalone_commands.py | 29 ++++++ .../glide/async_commands/transaction.py | 23 +++++ python/python/tests/test_async_client.py | 99 +++++++++++++++++++ python/python/tests/test_transaction.py | 15 ++- python/python/tests/utils/utils.py | 15 +++ 7 files changed, 215 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 46d70e4b44..4875aa4cfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,6 +31,7 @@ * Python: Added LMPOP and BLMPOP commands ([#1547](https://github.com/aws/glide-for-redis/pull/1547)) * Python: Added HSTRLEN command ([#1564](https://github.com/aws/glide-for-redis/pull/1564)) * Python: Added MSETNX command ([#1565](https://github.com/aws/glide-for-redis/pull/1565)) +* Python: Added FUNCTION LOAD command ([#1589](https://github.com/aws/glide-for-redis/pull/1589)) * Python: Added MOVE command ([#1566](https://github.com/aws/glide-for-redis/pull/1566)) * Python: Added EXPIRETIME, PEXPIRETIME commands ([#1587](https://github.com/aws/glide-for-redis/pull/1587)) * Python: Added LSET command ([#1584](https://github.com/aws/glide-for-redis/pull/1584)) diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index e010f1f54b..761d5301ca 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -314,6 +314,40 @@ async def echo( await self._execute_command(RequestType.Echo, [message], route), ) + async def function_load( + self, library_code: str, replace: bool = False, route: Optional[Route] = None + ) -> str: + """ + Loads a library to Redis. + + See https://valkey.io/docs/latest/commands/function-load/ for more details. + + Args: + library_code (str): The source code that implements the library. + replace (bool): Whether the given library should overwrite a library with the same name if + it already exists. + route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided, + in which case the client will route the command to the nodes defined by `route`. + + Returns: + str: The library name that was loaded. + + Examples: + >>> code = "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)" + >>> await client.function_load(code, True, RandomNode()) + "mylib" + + Since: Redis 7.0.0. + """ + return cast( + str, + await self._execute_command( + RequestType.FunctionLoad, + ["REPLACE", library_code] if replace else [library_code], + route, + ), + ) + async def time(self, route: Optional[Route] = None) -> TClusterResponse[List[str]]: """ Returns the server time. diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index f8776aadbb..e2757e5eb2 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -228,6 +228,35 @@ async def echo(self, message: str) -> str: """ return cast(str, await self._execute_command(RequestType.Echo, [message])) + async def function_load(self, library_code: str, replace: bool = False) -> str: + """ + Loads a library to Redis. + + See https://valkey.io/docs/latest/commands/function-load/ for more details. + + Args: + library_code (str): The source code that implements the library. + replace (bool): Whether the given library should overwrite a library with the same name if + it already exists. + + Returns: + str: The library name that was loaded. + + Examples: + >>> code = "#!lua name=mylib \n redis.register_function('myfunc', function(keys, args) return args[1] end)" + >>> await client.function_load(code, True) + "mylib" + + Since: Redis 7.0.0. + """ + return cast( + str, + await self._execute_command( + RequestType.FunctionLoad, + ["REPLACE", library_code] if replace else [library_code], + ), + ) + async def time(self) -> List[str]: """ Returns the server time. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index 63d2e0537d..dffca1d53e 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -1823,6 +1823,29 @@ def xlen(self: TTransaction, key: str) -> TTransaction: """ return self.append_command(RequestType.XLen, [key]) + def function_load( + self: TTransaction, library_code: str, replace: bool = False + ) -> TTransaction: + """ + Loads a library to Redis. + + See https://valkey.io/docs/latest/commands/function-load/ for more details. + + Args: + library_code (str): The source code that implements the library. + replace (bool): Whether the given library should overwrite a library with the same name if + it already exists. + + Commands response: + str: The library name that was loaded. + + Since: Redis 7.0.0. + """ + return self.append_command( + RequestType.FunctionLoad, + ["REPLACE", library_code] if replace else [library_code], + ) + def geoadd( self: TTransaction, key: str, diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index d1b2510655..0fbe8180f5 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -60,6 +60,7 @@ from tests.utils.utils import ( check_if_server_version_lt, compare_maps, + generate_lua_lib_code, get_first_result, get_random_string, is_single_response, @@ -5013,6 +5014,104 @@ async def test_object_refcount(self, redis_client: TRedisClient): refcount = await redis_client.object_refcount(string_key) assert refcount is not None and refcount >= 0 + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_function_load(self, redis_client: RedisClient): + # TODO: Test function with FCALL + # TODO: Test with FUNCTION LIST + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + + lib_name = f"mylib1C{get_random_string(5)}" + func_name = f"myfunc1c{get_random_string(5)}" + code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) + + assert await redis_client.function_load(code) == lib_name + + # TODO: change when FCALL, FCALL_RO is implemented + assert ( + await redis_client.custom_command(["FCALL", func_name, "0", "one", "two"]) + == "one" + ) + assert ( + await redis_client.custom_command( + ["FCALL_RO", func_name, "0", "one", "two"] + ) + == "one" + ) + + # TODO: add FUNCTION LIST once implemented + + # re-load library without overwriting + with pytest.raises(RequestError) as e: + await redis_client.function_load(code) + assert "Library '" + lib_name + "' already exists" in str(e) + + # re-load library with overwriting + assert await redis_client.function_load(code, True) == lib_name + + func2_name = f"myfunc2c{get_random_string(5)}" + new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)""" + new_code = generate_lua_lib_code( + lib_name, {func_name: "return args[1]", func2_name: "return #args"}, True + ) + + assert await redis_client.function_load(new_code, True) == lib_name + + @pytest.mark.parametrize("cluster_mode", [True]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + @pytest.mark.parametrize("single_route", [True, False]) + async def test_function_load_cluster_with_route( + self, redis_client: RedisClusterClient, single_route: bool + ): + # TODO: Test function with FCALL + # TODO: Test with FUNCTION LIST + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + return pytest.mark.skip(reason=f"Redis version required >= {min_version}") + + lib_name = f"mylib1C{get_random_string(5)}" + func_name = f"myfunc1c{get_random_string(5)}" + code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) + route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() + + assert await redis_client.function_load(code, False, route) == lib_name + + # TODO: change when FCALL, FCALL_RO is implemented. + assert ( + await redis_client.custom_command( + ["FCALL", func_name, "0", "one", "two"], + SlotKeyRoute(SlotType.PRIMARY, "1"), + ) + == "one" + ) + assert ( + await redis_client.custom_command( + ["FCALL_RO", func_name, "0", "one", "two"], + SlotKeyRoute(SlotType.PRIMARY, "1"), + ) + == "one" + ) + + # TODO: add FUNCTION LIST once implemented + + # re-load library without overwriting + with pytest.raises(RequestError) as e: + await redis_client.function_load(code, False, route) + assert "Library '" + lib_name + "' already exists" in str(e) + + # re-load library with overwriting + assert await redis_client.function_load(code, True, route) == lib_name + + func2_name = f"myfunc2c{get_random_string(5)}" + new_code = f"""{code}\n redis.register_function({func2_name}, function(keys, args) return #args end)""" + new_code = generate_lua_lib_code( + lib_name, {func_name: "return args[1]", func2_name: "return #args"}, True + ) + + assert await redis_client.function_load(new_code, True, route) == lib_name + class TestMultiKeyCommandCrossSlot: @pytest.mark.parametrize("cluster_mode", [True]) diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index 559362cc6f..5917a14a63 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -31,7 +31,11 @@ from glide.constants import OK, TResult from glide.redis_client import RedisClient, RedisClusterClient, TRedisClient from tests.conftest import create_client -from tests.utils.utils import check_if_server_version_lt, get_random_string +from tests.utils.utils import ( + check_if_server_version_lt, + generate_lua_lib_code, + get_random_string, +) async def transaction_test( @@ -63,8 +67,17 @@ async def transaction_test( value = datetime.now(timezone.utc).strftime("%m/%d/%Y, %H:%M:%S") value2 = get_random_string(5) value3 = get_random_string(5) + lib_name = f"mylib1C{get_random_string(5)}" + func_name = f"myfunc1c{get_random_string(5)}" + code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) args: List[TResult] = [] + if not await check_if_server_version_lt(redis_client, "7.0.0"): + transaction.function_load(code) + args.append(lib_name) + transaction.function_load(code, True) + args.append(lib_name) + transaction.dbsize() args.append(0) diff --git a/python/python/tests/utils/utils.py b/python/python/tests/utils/utils.py index ca003657a1..05bb68ca0e 100644 --- a/python/python/tests/utils/utils.py +++ b/python/python/tests/utils/utils.py @@ -113,3 +113,18 @@ def compare_maps( if map1 is None or map2 is None: return False return json.dumps(map1) == json.dumps(map2) + + +def generate_lua_lib_code( + lib_name: str, functions: Mapping[str, str], readonly: bool +) -> str: + code = f"#!lua name={lib_name}\n" + for function_name, function_body in functions.items(): + code += ( + f"redis.register_function{{ function_name = '{function_name}', callback = function(keys, args) " + f"{function_body} end" + ) + if readonly: + code += ", flags = { 'no-writes' }" + code += " }\n" + return code From 752514c9ed54b34478796fb0af8b768c32f3f83d Mon Sep 17 00:00:00 2001 From: Shoham Elias Date: Tue, 18 Jun 2024 14:16:13 +0000 Subject: [PATCH 2/6] Python: adds FUNCTION FLUSH command --- CHANGELOG.md | 1 + python/python/glide/__init__.py | 3 +- .../glide/async_commands/cluster_commands.py | 33 +++++++++- .../glide/async_commands/command_args.py | 15 +++++ .../async_commands/standalone_commands.py | 28 ++++++++- .../glide/async_commands/transaction.py | 23 ++++++- python/python/tests/test_async_client.py | 62 ++++++++++++++++++- python/python/tests/test_transaction.py | 8 ++- 8 files changed, 167 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4875aa4cfd..c3ea960f04 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,7 @@ * Python: Added HSTRLEN command ([#1564](https://github.com/aws/glide-for-redis/pull/1564)) * Python: Added MSETNX command ([#1565](https://github.com/aws/glide-for-redis/pull/1565)) * Python: Added FUNCTION LOAD command ([#1589](https://github.com/aws/glide-for-redis/pull/1589)) +* Python: Added FUNCTION FLUSH command ([#1590](https://github.com/aws/glide-for-redis/pull/1590)) * Python: Added MOVE command ([#1566](https://github.com/aws/glide-for-redis/pull/1566)) * Python: Added EXPIRETIME, PEXPIRETIME commands ([#1587](https://github.com/aws/glide-for-redis/pull/1587)) * Python: Added LSET command ([#1584](https://github.com/aws/glide-for-redis/pull/1584)) diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index 65bb5fac80..6b8c5ff2f8 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -1,7 +1,7 @@ # Copyright GLIDE-for-Redis Project Contributors - SPDX Identifier: Apache-2.0 from glide.async_commands.bitmap import BitmapIndexType, OffsetOptions -from glide.async_commands.command_args import Limit, ListDirection, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, ListDirection, OrderBy from glide.async_commands.core import ( ConditionalChange, ExpireOptions, @@ -103,6 +103,7 @@ "InfoSection", "InsertPosition", "json", + "FlushMode", "LexBoundary", "Limit", "ListDirection", diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index 761d5301ca..29ce3db6a3 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -4,7 +4,7 @@ from typing import Dict, List, Mapping, Optional, cast -from glide.async_commands.command_args import Limit, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, OrderBy from glide.async_commands.core import CoreCommands, InfoSection, _build_sort_args from glide.async_commands.transaction import BaseTransaction, ClusterTransaction from glide.constants import TOK, TClusterResponse, TResult, TSingleNodeRoute @@ -314,6 +314,37 @@ async def echo( await self._execute_command(RequestType.Echo, [message], route), ) + async def function_flush( + self, mode: Optional[FlushMode] = None, route: Optional[Route] = None + ) -> TOK: + """ + Deletes all function libraries. + + See https://valkey.io/docs/latest/commands/function-flush/ for more details. + + Args: + mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided, + in which case the client will route the command to the nodes defined by `route`. + + Returns: + TOK: A simple `OK`. + + Examples: + >>> await client.function_flush(FlushMode.SYNC) + "OK" + + Since: Redis 7.0.0. + """ + return cast( + TOK, + await self._execute_command( + RequestType.FunctionFlush, + [mode.value] if mode else [], + route, + ), + ) + async def function_load( self, library_code: str, replace: bool = False, route: Optional[Route] = None ) -> str: diff --git a/python/python/glide/async_commands/command_args.py b/python/python/glide/async_commands/command_args.py index 39d3e4982c..a7759c5e5a 100644 --- a/python/python/glide/async_commands/command_args.py +++ b/python/python/glide/async_commands/command_args.py @@ -63,3 +63,18 @@ class ListDirection(Enum): """ RIGHT: Represents the option that elements should be popped from or added to the right side of a list. """ + + +class FlushMode(Enum): + """ + Enumeration representing the flushing mode for `FLUSHALL`, `FLUSHDB` and `FUNCTION FLUSH` commands. + """ + + SYNC = "SYNC" + """ + Represents synchronous flushing mode. + """ + ASYNC = "ASYNC" + """ + Represents asynchronous flushing mode. + """ diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index e2757e5eb2..34a81833c8 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -4,7 +4,7 @@ from typing import Dict, List, Mapping, Optional, cast -from glide.async_commands.command_args import Limit, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, OrderBy from glide.async_commands.core import CoreCommands, InfoSection, _build_sort_args from glide.async_commands.transaction import BaseTransaction, Transaction from glide.constants import TOK, TResult @@ -228,6 +228,32 @@ async def echo(self, message: str) -> str: """ return cast(str, await self._execute_command(RequestType.Echo, [message])) + async def function_flush(self, mode: Optional[FlushMode] = None) -> TOK: + """ + Deletes all function libraries. + + See https://valkey.io/docs/latest/commands/function-flush/ for more details. + + Args: + mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + + Returns: + TOK: A simple `OK`. + + Examples: + >>> await client.function_flush(FlushMode.SYNC) + "OK" + + Since: Redis 7.0.0. + """ + return cast( + TOK, + await self._execute_command( + RequestType.FunctionFlush, + [mode.value] if mode else [], + ), + ) + async def function_load(self, library_code: str, replace: bool = False) -> str: """ Loads a library to Redis. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index dffca1d53e..69d2b4b00d 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -4,7 +4,7 @@ from typing import List, Mapping, Optional, Tuple, TypeVar, Union from glide.async_commands.bitmap import OffsetOptions -from glide.async_commands.command_args import Limit, ListDirection, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, ListDirection, OrderBy from glide.async_commands.core import ( ConditionalChange, ExpireOptions, @@ -1823,6 +1823,27 @@ def xlen(self: TTransaction, key: str) -> TTransaction: """ return self.append_command(RequestType.XLen, [key]) + def function_flush( + self: TTransaction, mode: Optional[FlushMode] = None + ) -> TTransaction: + """ + Deletes all function libraries. + + See https://valkey.io/docs/latest/commands/function-flush/ for more details. + + Args: + mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + + Commands response: + TOK: A simple `OK`. + + Since: Redis 7.0.0. + """ + return self.append_command( + RequestType.FunctionFlush, + [mode.value] if mode else [], + ) + def function_load( self: TTransaction, library_code: str, replace: bool = False ) -> TTransaction: diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index 0fbe8180f5..6e105b74e9 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -12,7 +12,7 @@ import pytest from glide import ClosingError, RequestError, Script from glide.async_commands.bitmap import BitmapIndexType, OffsetOptions -from glide.async_commands.command_args import Limit, ListDirection, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, ListDirection, OrderBy from glide.async_commands.core import ( ConditionalChange, ExpireOptions, @@ -5112,6 +5112,66 @@ async def test_function_load_cluster_with_route( assert await redis_client.function_load(new_code, True, route) == lib_name + @pytest.mark.parametrize("cluster_mode", [True, False]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + async def test_function_flush(self, redis_client: RedisClient): + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + pytest.skip(f"Redis version required >= {min_version}") + + lib_name = f"mylib1C{get_random_string(5)}" + func_name = f"myfunc1c{get_random_string(5)}" + code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) + + # Load the function + assert await redis_client.function_load(code) == lib_name + + # TODO: Ensure the function exists with FUNCTION LIST + + # Flush functions + assert await redis_client.function_flush(FlushMode.SYNC) == OK + assert await redis_client.function_flush(FlushMode.ASYNC) == OK + + # TODO: Ensure the function is no longer present with FUNCTION LIST + + # Attempt to re-load library without overwriting to ensure FLUSH was effective + assert await redis_client.function_load(code) == lib_name + + # Clean up by flushing functions again + await redis_client.function_flush() + + @pytest.mark.parametrize("cluster_mode", [True]) + @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) + @pytest.mark.parametrize("single_route", [True, False]) + async def test_function_flush_with_routing( + self, redis_client: RedisClusterClient, single_route: bool + ): + min_version = "7.0.0" + if await check_if_server_version_lt(redis_client, min_version): + pytest.skip(f"Redis version required >= {min_version}") + + lib_name = f"mylib1C{get_random_string(5)}" + func_name = f"myfunc1c{get_random_string(5)}" + code = generate_lua_lib_code(lib_name, {func_name: "return args[1]"}, True) + route = SlotKeyRoute(SlotType.PRIMARY, "1") if single_route else AllPrimaries() + + # Load the function + assert await redis_client.function_load(code, False, route) == lib_name + + # TODO: Ensure the function exists with FUNCTION LIST + + # Flush functions + assert await redis_client.function_flush(FlushMode.SYNC, route) == OK + assert await redis_client.function_flush(FlushMode.ASYNC, route) == OK + + # TODO: Ensure the function is no longer present with FUNCTION LIST + + # Attempt to re-load library without overwriting to ensure FLUSH was effective + assert await redis_client.function_load(code, False, route) == lib_name + + # Clean up by flushing functions again + assert await redis_client.function_flush(route=route) == OK + class TestMultiKeyCommandCrossSlot: @pytest.mark.parametrize("cluster_mode", [True]) diff --git a/python/python/tests/test_transaction.py b/python/python/tests/test_transaction.py index 5917a14a63..1d15b2b6c7 100644 --- a/python/python/tests/test_transaction.py +++ b/python/python/tests/test_transaction.py @@ -7,7 +7,7 @@ import pytest from glide import RequestError from glide.async_commands.bitmap import BitmapIndexType, OffsetOptions -from glide.async_commands.command_args import Limit, ListDirection, OrderBy +from glide.async_commands.command_args import FlushMode, Limit, ListDirection, OrderBy from glide.async_commands.core import InsertPosition, StreamAddOptions, TrimByMinId from glide.async_commands.sorted_set import ( AggregationType, @@ -77,6 +77,12 @@ async def transaction_test( args.append(lib_name) transaction.function_load(code, True) args.append(lib_name) + transaction.function_flush() + args.append(OK) + transaction.function_flush(FlushMode.ASYNC) + args.append(OK) + transaction.function_flush(FlushMode.SYNC) + args.append(OK) transaction.dbsize() args.append(0) From 59c73793a4c71ceef3ecfad0b08f507f40fa2a79 Mon Sep 17 00:00:00 2001 From: Yi-Pin Chen Date: Thu, 27 Jun 2024 15:58:16 -0700 Subject: [PATCH 3/6] Updated CHANGELOG.md --- CHANGELOG.md | 3 +-- python/python/tests/test_async_client.py | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70dfc2907a..ca4fb6153c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -31,8 +31,6 @@ * Python: Added LMPOP and BLMPOP commands ([#1547](https://github.com/aws/glide-for-redis/pull/1547)) * Python: Added HSTRLEN command ([#1564](https://github.com/aws/glide-for-redis/pull/1564)) * Python: Added MSETNX command ([#1565](https://github.com/aws/glide-for-redis/pull/1565)) -* Python: Added FUNCTION LOAD command ([#1589](https://github.com/aws/glide-for-redis/pull/1589)) -* Python: Added FUNCTION FLUSH command ([#1590](https://github.com/aws/glide-for-redis/pull/1590)) * Python: Added MOVE command ([#1566](https://github.com/aws/glide-for-redis/pull/1566)) * Python: Added EXPIRETIME, PEXPIRETIME commands ([#1587](https://github.com/aws/glide-for-redis/pull/1587)) * Python: Added LSET command ([#1584](https://github.com/aws/glide-for-redis/pull/1584)) @@ -62,6 +60,7 @@ * Python: Added FLUSHDB command ([#1680](https://github.com/aws/glide-for-redis/pull/1680)) * Python: Added XGROUP SETID command ([#1683](https://github.com/aws/glide-for-redis/pull/1683)) * Python: Added FUNCTION LOAD command ([#1699](https://github.com/aws/glide-for-redis/pull/1699)) +* Python: Added FUNCTION FLUSH command ([#1700](https://github.com/aws/glide-for-redis/pull/1700)) ### Breaking Changes * Node: Update XREAD to return a Map of Map ([#1494](https://github.com/aws/glide-for-redis/pull/1494)) diff --git a/python/python/tests/test_async_client.py b/python/python/tests/test_async_client.py index c1b1c178ae..198a6d329a 100644 --- a/python/python/tests/test_async_client.py +++ b/python/python/tests/test_async_client.py @@ -6454,7 +6454,7 @@ async def test_function_flush_with_routing( assert await redis_client.function_load(code, False, route) == lib_name # Clean up by flushing functions again - assert await redis_client.function_flush(route=route) == OK + assert await redis_client.function_flush(route=route) == OK @pytest.mark.parametrize("cluster_mode", [True, False]) @pytest.mark.parametrize("protocol", [ProtocolVersion.RESP2, ProtocolVersion.RESP3]) From 7ae9fc93cd579a3ff2ad260053fa14c89f252700 Mon Sep 17 00:00:00 2001 From: Yi-Pin Chen Date: Thu, 27 Jun 2024 16:05:35 -0700 Subject: [PATCH 4/6] Resolved merge issues related to FlushMode --- python/python/glide/__init__.py | 1 - .../python/glide/async_commands/command_args.py | 15 --------------- 2 files changed, 16 deletions(-) diff --git a/python/python/glide/__init__.py b/python/python/glide/__init__.py index f9e4b7499e..7b0510dbb1 100644 --- a/python/python/glide/__init__.py +++ b/python/python/glide/__init__.py @@ -152,7 +152,6 @@ "InfoSection", "InsertPosition", "json", - "FlushMode", "LexBoundary", "Limit", "ListDirection", diff --git a/python/python/glide/async_commands/command_args.py b/python/python/glide/async_commands/command_args.py index 17e8abfe24..ce76fd2d55 100644 --- a/python/python/glide/async_commands/command_args.py +++ b/python/python/glide/async_commands/command_args.py @@ -63,18 +63,3 @@ class ListDirection(Enum): """ RIGHT: Represents the option that elements should be popped from or added to the right side of a list. """ - - -class FlushMode(Enum): - """ - Enumeration representing the flushing mode for `FLUSHALL`, `FLUSHDB` and `FUNCTION FLUSH` commands. - """ - - SYNC = "SYNC" - """ - Represents synchronous flushing mode. - """ - ASYNC = "ASYNC" - """ - Represents asynchronous flushing mode. - """ From 3a583d14228a4b1874b962cbab9baa788b6edaf3 Mon Sep 17 00:00:00 2001 From: Yi-Pin Chen Date: Thu, 27 Jun 2024 16:15:17 -0700 Subject: [PATCH 5/6] Minor adjustments on command documentation --- python/python/glide/async_commands/cluster_commands.py | 4 ++-- python/python/glide/async_commands/standalone_commands.py | 2 +- python/python/glide/async_commands/transaction.py | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index 060bc20d44..dcc446bda1 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -362,7 +362,7 @@ async def function_flush( See https://valkey.io/docs/latest/commands/function-flush/ for more details. Args: - mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. route (Optional[Route]): The command will be routed to all primaries, unless `route` is provided, in which case the client will route the command to the nodes defined by `route`. @@ -370,7 +370,7 @@ async def function_flush( TOK: A simple `OK`. Examples: - >>> await client.function_flush(FlushMode.SYNC) + >>> await client.function_flush(SYNC) "OK" Since: Redis 7.0.0. diff --git a/python/python/glide/async_commands/standalone_commands.py b/python/python/glide/async_commands/standalone_commands.py index 2650ca8805..6bb9b2184e 100644 --- a/python/python/glide/async_commands/standalone_commands.py +++ b/python/python/glide/async_commands/standalone_commands.py @@ -269,7 +269,7 @@ async def function_flush(self, mode: Optional[FlushMode] = None) -> TOK: See https://valkey.io/docs/latest/commands/function-flush/ for more details. Args: - mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. Returns: TOK: A simple `OK`. diff --git a/python/python/glide/async_commands/transaction.py b/python/python/glide/async_commands/transaction.py index a663389ec0..72add969f9 100644 --- a/python/python/glide/async_commands/transaction.py +++ b/python/python/glide/async_commands/transaction.py @@ -1808,7 +1808,7 @@ def function_flush( See https://valkey.io/docs/latest/commands/function-flush/ for more details. Args: - mode (FlushMode): The flushing mode, could be either `FlushMode.SYNC` or `FlushMode.ASYNC`. + mode (Optional[FlushMode]): The flushing mode, could be either `SYNC` or `ASYNC`. Commands response: TOK: A simple `OK`. From 67fce760755f09125edffc9e747f7c5353f0420b Mon Sep 17 00:00:00 2001 From: Yi-Pin Chen Date: Thu, 27 Jun 2024 16:23:41 -0700 Subject: [PATCH 6/6] Revert one minor change in example. --- python/python/glide/async_commands/cluster_commands.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python/python/glide/async_commands/cluster_commands.py b/python/python/glide/async_commands/cluster_commands.py index dcc446bda1..fca7e80d81 100644 --- a/python/python/glide/async_commands/cluster_commands.py +++ b/python/python/glide/async_commands/cluster_commands.py @@ -370,7 +370,7 @@ async def function_flush( TOK: A simple `OK`. Examples: - >>> await client.function_flush(SYNC) + >>> await client.function_flush(FlushMode.SYNC) "OK" Since: Redis 7.0.0.