Skip to content

Commit 700045c

Browse files
authored
Backport 5.1 changes into master (#3406)
* Updated package version (#3389) * Fix bug with Redis Set commands returns List instead of Set (#3399) * Fix bug with Redis Set commands returns List instead of Set in RESP2 * Removed fixture, codestyle fixes * Fixed tests for async * Fixed asyncio cluster test cases * Added Sets alignment for RESP2 and RESP3 * Updated doctests * Fix bug with partial Hiredis availability (#3400) * Fix bug with partial Hiredis availability * Added yes flag * Codestyl fixes * Removed redundant check * Removed redundant checks associated with pack command * Updated condition to check the actual flag * Removed unused import * Fix bug with async pipeline and cluster fails with some commands (#3402) * Fix bug with async pipeline fails with some commands * Codestyl changes * Remove keys option in cluster context * Updated package version (#3403)
1 parent 2e46613 commit 700045c

16 files changed

+131
-83
lines changed

.github/workflows/integration.yaml

+33
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,21 @@ jobs:
9090
invoke ${{matrix.test-type}}-tests
9191
ls -1
9292
93+
- name: Run tests against hiredis < 3.0.0
94+
if: ${{ matrix.connection-type == 'hiredis' && matrix.python-version == '3.12'}}
95+
run: |
96+
pip uninstall hiredis -y
97+
pip install -U setuptools wheel
98+
pip install -r requirements.txt
99+
pip install -r dev_requirements.txt
100+
if [ "${{matrix.connection-type}}" == "hiredis" ]; then
101+
pip install "hiredis<3.0.0"
102+
fi
103+
invoke devenv
104+
sleep 10 # time to settle
105+
invoke ${{matrix.test-type}}-tests
106+
ls -1
107+
93108
- name: Upload test results and profiling data
94109
uses: actions/upload-artifact@v4
95110
with:
@@ -145,6 +160,24 @@ jobs:
145160
invoke ${{matrix.test-type}}-tests --protocol=3
146161
fi
147162
163+
- name: Run tests against hiredis < 3.0.0
164+
if: ${{ matrix.connection-type == 'hiredis' && matrix.python-version == '3.12'}}
165+
run: |
166+
pip uninstall hiredis -y
167+
pip install -U setuptools wheel
168+
pip install -r requirements.txt
169+
pip install -r dev_requirements.txt
170+
if [ "${{matrix.connection-type}}" == "hiredis" ]; then
171+
pip install "hiredis<3.0.0"
172+
fi
173+
invoke devenv
174+
sleep 10 # time to settle
175+
if [ "${{matrix.event-loop}}" == "uvloop" ]; then
176+
invoke ${{matrix.test-type}}-tests --uvloop --protocol=3
177+
else
178+
invoke ${{matrix.test-type}}-tests --protocol=3
179+
fi
180+
148181
- name: Upload test results and profiling data
149182
uses: actions/upload-artifact@v4
150183
with:

doctests/dt_set.py

+17-17
Original file line numberDiff line numberDiff line change
@@ -58,11 +58,11 @@
5858
r.sadd("bikes:racing:usa", "bike:1", "bike:4")
5959
# HIDE_END
6060
res7 = r.sinter("bikes:racing:france", "bikes:racing:usa")
61-
print(res7) # >>> ['bike:1']
61+
print(res7) # >>> {'bike:1'}
6262
# STEP_END
6363

6464
# REMOVE_START
65-
assert res7 == ["bike:1"]
65+
assert res7 == {"bike:1"}
6666
# REMOVE_END
6767

6868
# STEP_START scard
@@ -83,12 +83,12 @@
8383
print(res9) # >>> 3
8484

8585
res10 = r.smembers("bikes:racing:france")
86-
print(res10) # >>> ['bike:1', 'bike:2', 'bike:3']
86+
print(res10) # >>> {'bike:1', 'bike:2', 'bike:3'}
8787
# STEP_END
8888

8989
# REMOVE_START
9090
assert res9 == 3
91-
assert res10 == ['bike:1', 'bike:2', 'bike:3']
91+
assert res10 == {'bike:1', 'bike:2', 'bike:3'}
9292
# REMOVE_END
9393

9494
# STEP_START smismember
@@ -109,11 +109,11 @@
109109
r.sadd("bikes:racing:usa", "bike:1", "bike:4")
110110

111111
res13 = r.sdiff("bikes:racing:france", "bikes:racing:usa")
112-
print(res13) # >>> ['bike:2', 'bike:3']
112+
print(res13) # >>> {'bike:2', 'bike:3'}
113113
# STEP_END
114114

115115
# REMOVE_START
116-
assert res13 == ['bike:2', 'bike:3']
116+
assert res13 == {'bike:2', 'bike:3'}
117117
r.delete("bikes:racing:france")
118118
r.delete("bikes:racing:usa")
119119
# REMOVE_END
@@ -124,27 +124,27 @@
124124
r.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4")
125125

126126
res13 = r.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
127-
print(res13) # >>> ['bike:1']
127+
print(res13) # >>> {'bike:1'}
128128

129129
res14 = r.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
130-
print(res14) # >>> ['bike:1', 'bike:2', 'bike:3', 'bike:4']
130+
print(res14) # >>> {'bike:1', 'bike:2', 'bike:3', 'bike:4'}
131131

132132
res15 = r.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
133-
print(res15) # >>> []
133+
print(res15) # >>> {}
134134

135135
res16 = r.sdiff("bikes:racing:usa", "bikes:racing:france")
136-
print(res16) # >>> ['bike:4']
136+
print(res16) # >>> {'bike:4'}
137137

138138
res17 = r.sdiff("bikes:racing:france", "bikes:racing:usa")
139-
print(res17) # >>> ['bike:2', 'bike:3']
139+
print(res17) # >>> {'bike:2', 'bike:3'}
140140
# STEP_END
141141

142142
# REMOVE_START
143-
assert res13 == ['bike:1']
144-
assert res14 == ['bike:1', 'bike:2', 'bike:3', 'bike:4']
145-
assert res15 == []
146-
assert res16 == ['bike:4']
147-
assert res17 == ['bike:2', 'bike:3']
143+
assert res13 == {'bike:1'}
144+
assert res14 == {'bike:1', 'bike:2', 'bike:3', 'bike:4'}
145+
assert res15 == {}
146+
assert res16 == {'bike:4'}
147+
assert res17 == {'bike:2', 'bike:3'}
148148
r.delete("bikes:racing:france")
149149
r.delete("bikes:racing:usa")
150150
r.delete("bikes:racing:italy")
@@ -160,7 +160,7 @@
160160
print(res19) # >>> bike:3
161161

162162
res20 = r.smembers("bikes:racing:france")
163-
print(res20) # >>> ['bike:2', 'bike:4', 'bike:5']
163+
print(res20) # >>> {'bike:2', 'bike:4', 'bike:5'}
164164

165165
res21 = r.srandmember("bikes:racing:france")
166166
print(res21) # >>> bike:4

redis/_parsers/helpers.py

+6
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,9 @@ def string_keys_to_dict(key_string, callback):
785785

786786

787787
_RedisCallbacksRESP2 = {
788+
**string_keys_to_dict(
789+
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
790+
),
788791
**string_keys_to_dict(
789792
"ZDIFF ZINTER ZPOPMAX ZPOPMIN ZRANGE ZRANGEBYSCORE ZRANK ZREVRANGE "
790793
"ZREVRANGEBYSCORE ZREVRANK ZUNION",
@@ -829,6 +832,9 @@ def string_keys_to_dict(key_string, callback):
829832

830833

831834
_RedisCallbacksRESP3 = {
835+
**string_keys_to_dict(
836+
"SDIFF SINTER SMEMBERS SUNION", lambda r: r and set(r) or set()
837+
),
832838
**string_keys_to_dict(
833839
"ZRANGE ZINTER ZPOPMAX ZPOPMIN ZRANGEBYSCORE ZREVRANGE ZREVRANGEBYSCORE "
834840
"ZUNION HGETALL XREADGROUP",

redis/asyncio/client.py

+4
Original file line numberDiff line numberDiff line change
@@ -1423,6 +1423,10 @@ async def _execute_transaction( # noqa: C901
14231423
if not isinstance(r, Exception):
14241424
args, options = cmd
14251425
command_name = args[0]
1426+
1427+
# Remove keys entry, it needs only for cache.
1428+
options.pop("keys", None)
1429+
14261430
if command_name in self.response_callbacks:
14271431
r = self.response_callbacks[command_name](r, **options)
14281432
if inspect.isawaitable(r):

redis/cluster.py

+4
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,10 @@ def _execute_command(self, target_node, *args, **kwargs):
11631163
asking = False
11641164
connection.send_command(*args, **kwargs)
11651165
response = redis_node.parse_response(connection, command, **kwargs)
1166+
1167+
# Remove keys entry, it needs only for cache.
1168+
kwargs.pop("keys", None)
1169+
11661170
if command in self.cluster_response_callbacks:
11671171
response = self.cluster_response_callbacks[command](
11681172
response, **kwargs

redis/connection.py

+1-2
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
from .utils import (
3939
CRYPTOGRAPHY_AVAILABLE,
4040
HIREDIS_AVAILABLE,
41-
HIREDIS_PACK_AVAILABLE,
4241
SSL_AVAILABLE,
4342
compare_versions,
4443
ensure_string,
@@ -314,7 +313,7 @@ def __del__(self):
314313
def _construct_command_packer(self, packer):
315314
if packer is not None:
316315
return packer
317-
elif HIREDIS_PACK_AVAILABLE:
316+
elif HIREDIS_AVAILABLE:
318317
return HiredisRespSerializer()
319318
else:
320319
return PythonRespSerializer(self._buffer_cutoff, self.encoder.encode)

redis/utils.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88

99
# Only support Hiredis >= 3.0:
1010
HIREDIS_AVAILABLE = int(hiredis.__version__.split(".")[0]) >= 3
11-
HIREDIS_PACK_AVAILABLE = hasattr(hiredis, "pack_command")
11+
if not HIREDIS_AVAILABLE:
12+
raise ImportError("hiredis package should be >= 3.0.0")
1213
except ImportError:
1314
HIREDIS_AVAILABLE = False
14-
HIREDIS_PACK_AVAILABLE = False
1515

1616
try:
1717
import ssl # noqa

setup.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
long_description_content_type="text/markdown",
99
keywords=["Redis", "key-value store", "database"],
1010
license="MIT",
11-
version="5.1.0b7",
11+
version="5.1.1",
1212
packages=find_packages(
1313
include=[
1414
"redis",

tests/test_asyncio/test_cluster.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -1752,38 +1752,38 @@ async def test_cluster_rpoplpush(self, r: RedisCluster) -> None:
17521752

17531753
async def test_cluster_sdiff(self, r: RedisCluster) -> None:
17541754
await r.sadd("{foo}a", "1", "2", "3")
1755-
assert set(await r.sdiff("{foo}a", "{foo}b")) == {b"1", b"2", b"3"}
1755+
assert await r.sdiff("{foo}a", "{foo}b") == {b"1", b"2", b"3"}
17561756
await r.sadd("{foo}b", "2", "3")
1757-
assert await r.sdiff("{foo}a", "{foo}b") == [b"1"]
1757+
assert await r.sdiff("{foo}a", "{foo}b") == {b"1"}
17581758

17591759
async def test_cluster_sdiffstore(self, r: RedisCluster) -> None:
17601760
await r.sadd("{foo}a", "1", "2", "3")
17611761
assert await r.sdiffstore("{foo}c", "{foo}a", "{foo}b") == 3
1762-
assert set(await r.smembers("{foo}c")) == {b"1", b"2", b"3"}
1762+
assert await r.smembers("{foo}c") == {b"1", b"2", b"3"}
17631763
await r.sadd("{foo}b", "2", "3")
17641764
assert await r.sdiffstore("{foo}c", "{foo}a", "{foo}b") == 1
1765-
assert await r.smembers("{foo}c") == [b"1"]
1765+
assert await r.smembers("{foo}c") == {b"1"}
17661766

17671767
async def test_cluster_sinter(self, r: RedisCluster) -> None:
17681768
await r.sadd("{foo}a", "1", "2", "3")
1769-
assert await r.sinter("{foo}a", "{foo}b") == []
1769+
assert await r.sinter("{foo}a", "{foo}b") == set()
17701770
await r.sadd("{foo}b", "2", "3")
1771-
assert set(await r.sinter("{foo}a", "{foo}b")) == {b"2", b"3"}
1771+
assert await r.sinter("{foo}a", "{foo}b") == {b"2", b"3"}
17721772

17731773
async def test_cluster_sinterstore(self, r: RedisCluster) -> None:
17741774
await r.sadd("{foo}a", "1", "2", "3")
17751775
assert await r.sinterstore("{foo}c", "{foo}a", "{foo}b") == 0
1776-
assert await r.smembers("{foo}c") == []
1776+
assert await r.smembers("{foo}c") == set()
17771777
await r.sadd("{foo}b", "2", "3")
17781778
assert await r.sinterstore("{foo}c", "{foo}a", "{foo}b") == 2
1779-
assert set(await r.smembers("{foo}c")) == {b"2", b"3"}
1779+
assert await r.smembers("{foo}c") == {b"2", b"3"}
17801780

17811781
async def test_cluster_smove(self, r: RedisCluster) -> None:
17821782
await r.sadd("{foo}a", "a1", "a2")
17831783
await r.sadd("{foo}b", "b1", "b2")
17841784
assert await r.smove("{foo}a", "{foo}b", "a1")
1785-
assert await r.smembers("{foo}a") == [b"a2"]
1786-
assert set(await r.smembers("{foo}b")) == {b"b1", b"b2", b"a1"}
1785+
assert await r.smembers("{foo}a") == {b"a2"}
1786+
assert await r.smembers("{foo}b") == {b"b1", b"b2", b"a1"}
17871787

17881788
async def test_cluster_sunion(self, r: RedisCluster) -> None:
17891789
await r.sadd("{foo}a", "1", "2")

tests/test_asyncio/test_commands.py

+10-10
Original file line numberDiff line numberDiff line change
@@ -1415,34 +1415,34 @@ async def test_scard(self, r: redis.Redis):
14151415
@pytest.mark.onlynoncluster
14161416
async def test_sdiff(self, r: redis.Redis):
14171417
await r.sadd("a", "1", "2", "3")
1418-
assert set(await r.sdiff("a", "b")) == {b"1", b"2", b"3"}
1418+
assert await r.sdiff("a", "b") == {b"1", b"2", b"3"}
14191419
await r.sadd("b", "2", "3")
1420-
assert await r.sdiff("a", "b") == [b"1"]
1420+
assert await r.sdiff("a", "b") == {b"1"}
14211421

14221422
@pytest.mark.onlynoncluster
14231423
async def test_sdiffstore(self, r: redis.Redis):
14241424
await r.sadd("a", "1", "2", "3")
14251425
assert await r.sdiffstore("c", "a", "b") == 3
1426-
assert set(await r.smembers("c")) == {b"1", b"2", b"3"}
1426+
assert await r.smembers("c") == {b"1", b"2", b"3"}
14271427
await r.sadd("b", "2", "3")
14281428
assert await r.sdiffstore("c", "a", "b") == 1
1429-
assert await r.smembers("c") == [b"1"]
1429+
assert await r.smembers("c") == {b"1"}
14301430

14311431
@pytest.mark.onlynoncluster
14321432
async def test_sinter(self, r: redis.Redis):
14331433
await r.sadd("a", "1", "2", "3")
1434-
assert await r.sinter("a", "b") == []
1434+
assert await r.sinter("a", "b") == set()
14351435
await r.sadd("b", "2", "3")
1436-
assert set(await r.sinter("a", "b")) == {b"2", b"3"}
1436+
assert await r.sinter("a", "b") == {b"2", b"3"}
14371437

14381438
@pytest.mark.onlynoncluster
14391439
async def test_sinterstore(self, r: redis.Redis):
14401440
await r.sadd("a", "1", "2", "3")
14411441
assert await r.sinterstore("c", "a", "b") == 0
1442-
assert await r.smembers("c") == []
1442+
assert await r.smembers("c") == set()
14431443
await r.sadd("b", "2", "3")
14441444
assert await r.sinterstore("c", "a", "b") == 2
1445-
assert set(await r.smembers("c")) == {b"2", b"3"}
1445+
assert await r.smembers("c") == {b"2", b"3"}
14461446

14471447
async def test_sismember(self, r: redis.Redis):
14481448
await r.sadd("a", "1", "2", "3")
@@ -1460,8 +1460,8 @@ async def test_smove(self, r: redis.Redis):
14601460
await r.sadd("a", "a1", "a2")
14611461
await r.sadd("b", "b1", "b2")
14621462
assert await r.smove("a", "b", "a1")
1463-
assert await r.smembers("a") == [b"a2"]
1464-
assert set(await r.smembers("b")) == {b"b1", b"b2", b"a1"}
1463+
assert await r.smembers("a") == {b"a2"}
1464+
assert await r.smembers("b") == {b"b1", b"b2", b"a1"}
14651465

14661466
async def test_spop(self, r: redis.Redis):
14671467
s = [b"1", b"2", b"3"]

tests/test_asyncio/test_pipeline.py

+10
Original file line numberDiff line numberDiff line change
@@ -417,3 +417,13 @@ async def test_pipeline_discard(self, r):
417417
response = await pipe.execute()
418418
assert response[0]
419419
assert await r.get("foo") == b"bar"
420+
421+
@pytest.mark.onlynoncluster
422+
async def test_send_set_commands_over_async_pipeline(self, r: redis.asyncio.Redis):
423+
pipe = r.pipeline()
424+
pipe.hset("hash:1", "foo", "bar")
425+
pipe.hset("hash:1", "bar", "foo")
426+
pipe.hset("hash:1", "baz", "bar")
427+
pipe.hgetall("hash:1")
428+
resp = await pipe.execute()
429+
assert resp == [1, 1, 1, {b"bar": b"foo", b"baz": b"bar", b"foo": b"bar"}]

tests/test_cache.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ def r(request):
4141

4242
@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only")
4343
@pytest.mark.onlynoncluster
44-
# @skip_if_resp_version(2)
44+
@skip_if_resp_version(2)
4545
@skip_if_server_version_lt("7.4.0")
4646
class TestCache:
4747
@pytest.mark.parametrize(

0 commit comments

Comments
 (0)