Skip to content

Commit 65bde88

Browse files
Update Type Hints for List Command Parameters from str to KeyT (#3848)
* Extending the typehints for list names from just strings to KeyT * Update tests/test_commands.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Skipping new test on cluster - some commands contain multi-node keys --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent 3537352 commit 65bde88

File tree

2 files changed

+112
-17
lines changed

2 files changed

+112
-17
lines changed

redis/commands/core.py

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2792,7 +2792,7 @@ def brpop(
27922792
return self.execute_command("BRPOP", *keys)
27932793

27942794
def brpoplpush(
2795-
self, src: str, dst: str, timeout: Optional[Number] = 0
2795+
self, src: KeyT, dst: KeyT, timeout: Optional[Number] = 0
27962796
) -> Union[Awaitable[Optional[str]], Optional[str]]:
27972797
"""
27982798
Pop a value off the tail of ``src``, push it on the head of ``dst``
@@ -2849,7 +2849,7 @@ def lmpop(
28492849
return self.execute_command("LMPOP", *cmd_args)
28502850

28512851
def lindex(
2852-
self, name: str, index: int
2852+
self, name: KeyT, index: int
28532853
) -> Union[Awaitable[Optional[str]], Optional[str]]:
28542854
"""
28552855
Return the item from list ``name`` at position ``index``
@@ -2862,7 +2862,7 @@ def lindex(
28622862
return self.execute_command("LINDEX", name, index, keys=[name])
28632863

28642864
def linsert(
2865-
self, name: str, where: str, refvalue: str, value: str
2865+
self, name: KeyT, where: str, refvalue: str, value: str
28662866
) -> Union[Awaitable[int], int]:
28672867
"""
28682868
Insert ``value`` in list ``name`` either immediately before or after
@@ -2875,7 +2875,7 @@ def linsert(
28752875
"""
28762876
return self.execute_command("LINSERT", name, where, refvalue, value)
28772877

2878-
def llen(self, name: str) -> Union[Awaitable[int], int]:
2878+
def llen(self, name: KeyT) -> Union[Awaitable[int], int]:
28792879
"""
28802880
Return the length of the list ``name``
28812881
@@ -2885,7 +2885,7 @@ def llen(self, name: str) -> Union[Awaitable[int], int]:
28852885

28862886
def lpop(
28872887
self,
2888-
name: str,
2888+
name: KeyT,
28892889
count: Optional[int] = None,
28902890
) -> Union[Awaitable[Union[str, List, None]], Union[str, List, None]]:
28912891
"""
@@ -2902,23 +2902,23 @@ def lpop(
29022902
else:
29032903
return self.execute_command("LPOP", name)
29042904

2905-
def lpush(self, name: str, *values: FieldT) -> Union[Awaitable[int], int]:
2905+
def lpush(self, name: KeyT, *values: FieldT) -> Union[Awaitable[int], int]:
29062906
"""
29072907
Push ``values`` onto the head of the list ``name``
29082908
29092909
For more information, see https://redis.io/commands/lpush
29102910
"""
29112911
return self.execute_command("LPUSH", name, *values)
29122912

2913-
def lpushx(self, name: str, *values: FieldT) -> Union[Awaitable[int], int]:
2913+
def lpushx(self, name: KeyT, *values: FieldT) -> Union[Awaitable[int], int]:
29142914
"""
29152915
Push ``value`` onto the head of the list ``name`` if ``name`` exists
29162916
29172917
For more information, see https://redis.io/commands/lpushx
29182918
"""
29192919
return self.execute_command("LPUSHX", name, *values)
29202920

2921-
def lrange(self, name: str, start: int, end: int) -> Union[Awaitable[list], list]:
2921+
def lrange(self, name: KeyT, start: int, end: int) -> Union[Awaitable[list], list]:
29222922
"""
29232923
Return a slice of the list ``name`` between
29242924
position ``start`` and ``end``
@@ -2930,7 +2930,7 @@ def lrange(self, name: str, start: int, end: int) -> Union[Awaitable[list], list
29302930
"""
29312931
return self.execute_command("LRANGE", name, start, end, keys=[name])
29322932

2933-
def lrem(self, name: str, count: int, value: str) -> Union[Awaitable[int], int]:
2933+
def lrem(self, name: KeyT, count: int, value: str) -> Union[Awaitable[int], int]:
29342934
"""
29352935
Remove the first ``count`` occurrences of elements equal to ``value``
29362936
from the list stored at ``name``.
@@ -2944,15 +2944,15 @@ def lrem(self, name: str, count: int, value: str) -> Union[Awaitable[int], int]:
29442944
"""
29452945
return self.execute_command("LREM", name, count, value)
29462946

2947-
def lset(self, name: str, index: int, value: str) -> Union[Awaitable[str], str]:
2947+
def lset(self, name: KeyT, index: int, value: str) -> Union[Awaitable[str], str]:
29482948
"""
29492949
Set element at ``index`` of list ``name`` to ``value``
29502950
29512951
For more information, see https://redis.io/commands/lset
29522952
"""
29532953
return self.execute_command("LSET", name, index, value)
29542954

2955-
def ltrim(self, name: str, start: int, end: int) -> Union[Awaitable[str], str]:
2955+
def ltrim(self, name: KeyT, start: int, end: int) -> Union[Awaitable[str], str]:
29562956
"""
29572957
Trim the list ``name``, removing all values not within the slice
29582958
between ``start`` and ``end``
@@ -2966,7 +2966,7 @@ def ltrim(self, name: str, start: int, end: int) -> Union[Awaitable[str], str]:
29662966

29672967
def rpop(
29682968
self,
2969-
name: str,
2969+
name: KeyT,
29702970
count: Optional[int] = None,
29712971
) -> Union[Awaitable[Union[str, List, None]], Union[str, List, None]]:
29722972
"""
@@ -2983,7 +2983,7 @@ def rpop(
29832983
else:
29842984
return self.execute_command("RPOP", name)
29852985

2986-
def rpoplpush(self, src: str, dst: str) -> Union[Awaitable[str], str]:
2986+
def rpoplpush(self, src: KeyT, dst: KeyT) -> Union[Awaitable[str], str]:
29872987
"""
29882988
RPOP a value off of the ``src`` list and atomically LPUSH it
29892989
on to the ``dst`` list. Returns the value.
@@ -2992,15 +2992,15 @@ def rpoplpush(self, src: str, dst: str) -> Union[Awaitable[str], str]:
29922992
"""
29932993
return self.execute_command("RPOPLPUSH", src, dst)
29942994

2995-
def rpush(self, name: str, *values: FieldT) -> Union[Awaitable[int], int]:
2995+
def rpush(self, name: KeyT, *values: FieldT) -> Union[Awaitable[int], int]:
29962996
"""
29972997
Push ``values`` onto the tail of the list ``name``
29982998
29992999
For more information, see https://redis.io/commands/rpush
30003000
"""
30013001
return self.execute_command("RPUSH", name, *values)
30023002

3003-
def rpushx(self, name: str, *values: str) -> Union[Awaitable[int], int]:
3003+
def rpushx(self, name: KeyT, *values: str) -> Union[Awaitable[int], int]:
30043004
"""
30053005
Push ``value`` onto the tail of the list ``name`` if ``name`` exists
30063006
@@ -3010,7 +3010,7 @@ def rpushx(self, name: str, *values: str) -> Union[Awaitable[int], int]:
30103010

30113011
def lpos(
30123012
self,
3013-
name: str,
3013+
name: KeyT,
30143014
value: str,
30153015
rank: Optional[int] = None,
30163016
count: Optional[int] = None,
@@ -3055,7 +3055,7 @@ def lpos(
30553055

30563056
def sort(
30573057
self,
3058-
name: str,
3058+
name: KeyT,
30593059
start: Optional[int] = None,
30603060
num: Optional[int] = None,
30613061
by: Optional[str] = None,

tests/test_commands.py

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2892,6 +2892,8 @@ def test_lrange(self, r):
28922892
assert r.lrange("a", 0, 2) == [b"1", b"2", b"3"]
28932893
assert r.lrange("a", 2, 10) == [b"3", b"4", b"5"]
28942894
assert r.lrange("a", 0, -1) == [b"1", b"2", b"3", b"4", b"5"]
2895+
r.rpush(b"345", "12", "22", "32", "42", "52")
2896+
assert r.lrange(b"345", 0, 0) == [b"12"]
28952897

28962898
def test_lrem(self, r):
28972899
r.rpush("a", "Z", "b", "Z", "Z", "c", "Z", "Z")
@@ -2984,6 +2986,99 @@ def test_rpushx(self, r):
29842986
assert r.rpushx("a", "4") == 4
29852987
assert r.lrange("a", 0, -1) == [b"1", b"2", b"3", b"4"]
29862988

2989+
@pytest.mark.onlynoncluster
2990+
def test_lists_with_byte_keys(self, r):
2991+
r.rpush(b"b", b"1", b"2", b"3")
2992+
assert r.lrange(b"b", 0, -1) == [b"1", b"2", b"3"]
2993+
# LPOS command with byte keys
2994+
assert r.lpos(b"b", b"2") == 1
2995+
assert r.lpos(b"b", b"2", rank=1) == 1
2996+
assert r.lpos(b"b", b"2", rank=2) is None
2997+
# LCS command with byte keys
2998+
r.set(b"key1", b"ohmytext")
2999+
r.set(b"key2", b"mynewtext")
3000+
assert r.lcs(b"key1", b"key2") == b"mytext"
3001+
# TYPE command with byte keys
3002+
assert r.type(b"b") == b"list"
3003+
assert r.type(b"key1") == b"string"
3004+
# SCAN command with byte keys
3005+
r.set(b"scan_key1", b"value1")
3006+
r.set(b"scan_key2", b"value2")
3007+
cursor, keys = r.scan(match=b"scan_key*")
3008+
assert cursor == 0
3009+
assert set(keys) == {b"scan_key1", b"scan_key2"}
3010+
# PEXPIRETIME command with byte keys
3011+
r.set(b"expire_key", b"value")
3012+
r.pexpire(b"expire_key", 10000)
3013+
pexpiretime = r.pexpiretime(b"expire_key")
3014+
assert pexpiretime > 0
3015+
# LMOVE command with byte keys (src and dest)
3016+
r.rpush(b"list_src", b"a", b"b", b"c")
3017+
r.rpush(b"list_dest", b"x")
3018+
moved = r.lmove(b"list_src", b"list_dest", src=b"LEFT", dest=b"RIGHT")
3019+
assert moved == b"a"
3020+
assert r.lrange(b"list_dest", 0, -1) == [b"x", b"a"]
3021+
# SMOVE command with byte keys (src and dst)
3022+
r.sadd(b"set_src", b"member1", b"member2")
3023+
r.sadd(b"set_dest", b"member3")
3024+
assert r.smove(b"set_src", b"set_dest", b"member1") == 1
3025+
assert b"member1" in r.smembers(b"set_dest")
3026+
3027+
@pytest.mark.onlynoncluster
3028+
def test_lists_with_memoryview_keys(self, r):
3029+
# Create memoryview objects for key names
3030+
mv_b = memoryview(b"b")
3031+
mv_key1 = memoryview(b"key1")
3032+
mv_key2 = memoryview(b"key2")
3033+
mv_scan_key1 = memoryview(b"scan_key1")
3034+
mv_scan_key2 = memoryview(b"scan_key2")
3035+
mv_expire_key = memoryview(b"expire_key")
3036+
mv_list_src = memoryview(b"list_src")
3037+
mv_list_dest = memoryview(b"list_dest")
3038+
mv_set_src = memoryview(b"set_src")
3039+
mv_set_dest = memoryview(b"set_dest")
3040+
3041+
r.rpush(mv_b, b"1", b"2", b"3")
3042+
assert r.lrange(mv_b, 0, -1) == [b"1", b"2", b"3"]
3043+
# LPOS command with memoryview keys
3044+
assert r.lpos(mv_b, b"2") == 1
3045+
assert r.lpos(mv_b, b"2", rank=1) == 1
3046+
assert r.lpos(mv_b, b"2", rank=2) is None
3047+
# LCS command with memoryview keys
3048+
r.set(mv_key1, b"ohmytext")
3049+
r.set(mv_key2, b"mynewtext")
3050+
assert r.lcs(mv_key1, mv_key2) == b"mytext"
3051+
# TYPE command with memoryview keys
3052+
assert r.type(mv_b) == b"list"
3053+
assert r.type(mv_key1) == b"string"
3054+
# SCAN command with memoryview keys
3055+
r.set(mv_scan_key1, b"value1")
3056+
r.set(mv_scan_key2, b"value2")
3057+
cursor, keys = r.scan(match=memoryview(b"scan_key*"))
3058+
assert cursor == 0
3059+
assert set(keys) == {b"scan_key1", b"scan_key2"}
3060+
# PEXPIRETIME command with memoryview keys
3061+
r.set(mv_expire_key, b"value")
3062+
r.pexpire(mv_expire_key, 10000)
3063+
pexpiretime = r.pexpiretime(mv_expire_key)
3064+
assert pexpiretime > 0
3065+
# LMOVE command with memoryview keys (src and dest)
3066+
r.rpush(mv_list_src, b"a", b"b", b"c")
3067+
r.rpush(mv_list_dest, b"x")
3068+
moved = r.lmove(
3069+
mv_list_src,
3070+
mv_list_dest,
3071+
src=memoryview(b"LEFT"),
3072+
dest=memoryview(b"RIGHT"),
3073+
)
3074+
assert moved == b"a"
3075+
assert r.lrange(mv_list_dest, 0, -1) == [b"x", b"a"]
3076+
# SMOVE command with memoryview keys (src and dst)
3077+
r.sadd(mv_set_src, b"member1", b"member2")
3078+
r.sadd(mv_set_dest, b"member3")
3079+
assert r.smove(mv_set_src, mv_set_dest, b"member1") == 1
3080+
assert b"member1" in r.smembers(mv_set_dest)
3081+
29873082
# SCAN COMMANDS
29883083
@pytest.mark.onlynoncluster
29893084
@skip_if_server_version_lt("2.8.0")

0 commit comments

Comments
 (0)