Skip to content

Commit cbed9dc

Browse files
committed
Merge branch 'master' of github.com:redis/redis-py into vv-tba-support
2 parents 63059d6 + 8f2276e commit cbed9dc

File tree

7 files changed

+151
-22
lines changed

7 files changed

+151
-22
lines changed

doctests/trans_pipe.py

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
# EXAMPLE: pipe_trans_tutorial
2+
# HIDE_START
3+
"""
4+
Code samples for vector database quickstart pages:
5+
https://redis.io/docs/latest/develop/get-started/vector-database/
6+
"""
7+
# HIDE_END
8+
import redis
9+
10+
# STEP_START basic_pipe
11+
r = redis.Redis(decode_responses=True)
12+
# REMOVE_START
13+
for i in range(5):
14+
r.delete(f"seat:{i}")
15+
16+
r.delete("shellpath")
17+
# REMOVE_END
18+
19+
pipe = r.pipeline()
20+
21+
for i in range(5):
22+
pipe.set(f"seat:{i}", f"#{i}")
23+
24+
set_5_result = pipe.execute()
25+
print(set_5_result) # >>> [True, True, True, True, True]
26+
27+
pipe = r.pipeline()
28+
29+
# "Chain" pipeline commands together.
30+
get_3_result = pipe.get("seat:0").get("seat:3").get("seat:4").execute()
31+
print(get_3_result) # >>> ['#0', '#3', '#4']
32+
# STEP_END
33+
# REMOVE_START
34+
assert set_5_result == [True, True, True, True, True]
35+
assert get_3_result == ['#0', '#3', '#4']
36+
# REMOVE_END
37+
38+
# STEP_START trans_watch
39+
r.set("shellpath", "/usr/syscmds/")
40+
41+
with r.pipeline() as pipe:
42+
# Repeat until successful.
43+
while True:
44+
try:
45+
# Watch the key we are about to change.
46+
pipe.watch("shellpath")
47+
48+
# The pipeline executes commands directly (instead of
49+
# buffering them) from immediately after the `watch()`
50+
# call until we begin the transaction.
51+
current_path = pipe.get("shellpath")
52+
new_path = current_path + ":/usr/mycmds/"
53+
54+
# Start the transaction, which will enable buffering
55+
# again for the remaining commands.
56+
pipe.multi()
57+
58+
pipe.set("shellpath", new_path)
59+
60+
pipe.execute()
61+
62+
# The transaction succeeded, so break out of the loop.
63+
break
64+
except redis.WatchError:
65+
# The transaction failed, so continue with the next attempt.
66+
continue
67+
68+
get_path_result = r.get("shellpath")
69+
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
70+
# STEP_END
71+
# REMOVE_START
72+
assert get_path_result == '/usr/syscmds/:/usr/mycmds/'
73+
r.delete("shellpath")
74+
# REMOVE_END
75+
76+
# STEP_START watch_conv_method
77+
r.set("shellpath", "/usr/syscmds/")
78+
79+
80+
def watched_sequence(pipe):
81+
current_path = pipe.get("shellpath")
82+
new_path = current_path + ":/usr/mycmds/"
83+
84+
pipe.multi()
85+
86+
pipe.set("shellpath", new_path)
87+
88+
89+
trans_result = r.transaction(watched_sequence, "shellpath")
90+
print(trans_result) # True
91+
92+
get_path_result = r.get("shellpath")
93+
print(get_path_result) # >>> '/usr/syscmds/:/usr/mycmds/'
94+
# REMOVE_START
95+
assert trans_result
96+
assert get_path_result == '/usr/syscmds/:/usr/mycmds/'
97+
# REMOVE_END
98+
# STEP_END

redis/_parsers/helpers.py

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -396,13 +396,20 @@ def parse_item(item):
396396
# an O(N) complexity) instead of the command.
397397
if isinstance(item[3], list):
398398
result["command"] = space.join(item[3])
399-
result["client_address"] = item[4]
400-
result["client_name"] = item[5]
399+
400+
# These fields are optional, depends on environment.
401+
if len(item) >= 6:
402+
result["client_address"] = item[4]
403+
result["client_name"] = item[5]
401404
else:
402405
result["complexity"] = item[3]
403406
result["command"] = space.join(item[4])
404-
result["client_address"] = item[5]
405-
result["client_name"] = item[6]
407+
408+
# These fields are optional, depends on environment.
409+
if len(item) >= 7:
410+
result["client_address"] = item[5]
411+
result["client_name"] = item[6]
412+
406413
return result
407414

408415
return [parse_item(item) for item in response]

redis/asyncio/connection.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,13 @@ def __del__(self, _warnings: Any = warnings):
220220
_warnings.warn(
221221
f"unclosed Connection {self!r}", ResourceWarning, source=self
222222
)
223-
self._close()
223+
224+
try:
225+
asyncio.get_running_loop()
226+
self._close()
227+
except RuntimeError:
228+
# No actions been taken if pool already closed.
229+
pass
224230

225231
def _close(self):
226232
"""

redis/asyncio/sentinel.py

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,7 @@ def __init__(self, **kwargs):
2929
super().__init__(**kwargs)
3030

3131
def __repr__(self):
32-
pool = self.connection_pool
33-
s = (
34-
f"<{self.__class__.__module__}.{self.__class__.__name__}"
35-
f"(service={pool.service_name}"
36-
)
32+
s = f"<{self.__class__.__module__}.{self.__class__.__name__}"
3733
if self.host:
3834
host_info = f",host={self.host},port={self.port}"
3935
s += host_info

tests/test_asyncio/test_hash.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import asyncio
2+
import math
23
from datetime import datetime, timedelta
34

45
from tests.conftest import skip_if_server_version_lt
@@ -128,9 +129,9 @@ async def test_hpexpire_multiple_fields(r):
128129
async def test_hexpireat_basic(r):
129130
await r.delete("test:hash")
130131
await r.hset("test:hash", mapping={"field1": "value1", "field2": "value2"})
131-
exp_time = int((datetime.now() + timedelta(seconds=1)).timestamp())
132+
exp_time = math.ceil((datetime.now() + timedelta(seconds=1)).timestamp())
132133
assert await r.hexpireat("test:hash", exp_time, "field1") == [1]
133-
await asyncio.sleep(1.1)
134+
await asyncio.sleep(2.1)
134135
assert await r.hexists("test:hash", "field1") is False
135136
assert await r.hexists("test:hash", "field2") is True
136137

@@ -139,9 +140,9 @@ async def test_hexpireat_basic(r):
139140
async def test_hexpireat_with_datetime(r):
140141
await r.delete("test:hash")
141142
await r.hset("test:hash", mapping={"field1": "value1", "field2": "value2"})
142-
exp_time = datetime.now() + timedelta(seconds=1)
143+
exp_time = (datetime.now() + timedelta(seconds=2)).replace(microsecond=0)
143144
assert await r.hexpireat("test:hash", exp_time, "field1") == [1]
144-
await asyncio.sleep(1.1)
145+
await asyncio.sleep(2.1)
145146
assert await r.hexists("test:hash", "field1") is False
146147
assert await r.hexists("test:hash", "field2") is True
147148

@@ -175,9 +176,9 @@ async def test_hexpireat_multiple_fields(r):
175176
"test:hash",
176177
mapping={"field1": "value1", "field2": "value2", "field3": "value3"},
177178
)
178-
exp_time = int((datetime.now() + timedelta(seconds=1)).timestamp())
179+
exp_time = math.ceil((datetime.now() + timedelta(seconds=1)).timestamp())
179180
assert await r.hexpireat("test:hash", exp_time, "field1", "field2") == [1, 1]
180-
await asyncio.sleep(1.5)
181+
await asyncio.sleep(2.1)
181182
assert await r.hexists("test:hash", "field1") is False
182183
assert await r.hexists("test:hash", "field2") is False
183184
assert await r.hexists("test:hash", "field3") is True

tests/test_asyncio/test_sentinel.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -264,3 +264,23 @@ async def mock_disconnect():
264264

265265
assert calls == 1
266266
await pool.disconnect()
267+
268+
269+
@pytest.mark.onlynoncluster
270+
async def test_repr_correctly_represents_connection_object(sentinel):
271+
pool = SentinelConnectionPool("mymaster", sentinel)
272+
connection = await pool.get_connection("PING")
273+
274+
assert (
275+
str(connection)
276+
== "<redis.asyncio.sentinel.SentinelManagedConnection,host=127.0.0.1,port=6379)>" # noqa: E501
277+
)
278+
assert connection.connection_pool == pool
279+
await pool.release(connection)
280+
281+
del pool
282+
283+
assert (
284+
str(connection)
285+
== "<redis.asyncio.sentinel.SentinelManagedConnection,host=127.0.0.1,port=6379)>" # noqa: E501
286+
)

tests/test_hash.py

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import math
12
import time
23
from datetime import datetime, timedelta
34

@@ -147,9 +148,9 @@ def test_hpexpire_multiple_condition_flags_error(r):
147148
def test_hexpireat_basic(r):
148149
r.delete("test:hash")
149150
r.hset("test:hash", mapping={"field1": "value1", "field2": "value2"})
150-
exp_time = int((datetime.now() + timedelta(seconds=1)).timestamp())
151+
exp_time = math.ceil((datetime.now() + timedelta(seconds=1)).timestamp())
151152
assert r.hexpireat("test:hash", exp_time, "field1") == [1]
152-
time.sleep(1.1)
153+
time.sleep(2.1)
153154
assert r.hexists("test:hash", "field1") is False
154155
assert r.hexists("test:hash", "field2") is True
155156

@@ -158,9 +159,9 @@ def test_hexpireat_basic(r):
158159
def test_hexpireat_with_datetime(r):
159160
r.delete("test:hash")
160161
r.hset("test:hash", mapping={"field1": "value1", "field2": "value2"})
161-
exp_time = datetime.now() + timedelta(seconds=1)
162+
exp_time = (datetime.now() + timedelta(seconds=2)).replace(microsecond=0)
162163
assert r.hexpireat("test:hash", exp_time, "field1") == [1]
163-
time.sleep(1.1)
164+
time.sleep(2.1)
164165
assert r.hexists("test:hash", "field1") is False
165166
assert r.hexists("test:hash", "field2") is True
166167

@@ -194,9 +195,9 @@ def test_hexpireat_multiple_fields(r):
194195
"test:hash",
195196
mapping={"field1": "value1", "field2": "value2", "field3": "value3"},
196197
)
197-
exp_time = int((datetime.now() + timedelta(seconds=1)).timestamp())
198+
exp_time = math.ceil((datetime.now() + timedelta(seconds=1)).timestamp())
198199
assert r.hexpireat("test:hash", exp_time, "field1", "field2") == [1, 1]
199-
time.sleep(1.1)
200+
time.sleep(2.1)
200201
assert r.hexists("test:hash", "field1") is False
201202
assert r.hexists("test:hash", "field2") is False
202203
assert r.hexists("test:hash", "field3") is True

0 commit comments

Comments
 (0)