Skip to content

Commit e9d74ac

Browse files
committed
use from_pool() class method instead
1 parent 4a381e1 commit e9d74ac

File tree

8 files changed

+93
-59
lines changed

8 files changed

+93
-59
lines changed

docs/examples/asyncio_examples.ipynb

+2-2
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
"cell_type": "markdown",
4949
"metadata": {},
5050
"source": [
51-
"If you create custom `ConnectionPool` for the `Redis` instance to use, use the `from_pool` argument. This will cause the pool to be disconnected along with the Redis instance. Disconnecting the connection pool simply disconnects all connections hosted in the pool."
51+
"If you create custom `ConnectionPool` for the `Redis` instance to use alone, use the `from_pool` class method to create it. This will cause the pool to be disconnected along with the Redis instance. Disconnecting the connection pool simply disconnects all connections hosted in the pool."
5252
]
5353
},
5454
{
@@ -60,7 +60,7 @@
6060
"import redis.asyncio as redis\n",
6161
"\n",
6262
"pool = redis.ConnectionPool.from_url(\"redis://localhost\")\n",
63-
"connection = redis.Redis(from_pool=pool)\n",
63+
"connection = redis.Redis.from_pool(pool)\n",
6464
"await connection.close()"
6565
]
6666
},

redis/asyncio/client.py

+27-24
Original file line numberDiff line numberDiff line change
@@ -159,10 +159,28 @@ class initializer. In the case of conflicting arguments, querystring
159159
160160
"""
161161
connection_pool = ConnectionPool.from_url(url, **kwargs)
162-
return cls(
163-
from_pool=connection_pool,
162+
client = cls(
163+
connection_pool=connection_pool,
164164
single_connection_client=single_connection_client,
165165
)
166+
client.auto_close_connection_pool = True
167+
return client
168+
169+
@classmethod
170+
def from_pool(
171+
cls: Type["Redis"],
172+
connection_pool: ConnectionPool,
173+
) -> "Redis":
174+
"""
175+
Return a Redis client from the given connection pool.
176+
The Redis client will take ownership of the connection pool and
177+
close it when the Redis client is closed.
178+
"""
179+
client = cls(
180+
connection_pool=connection_pool,
181+
)
182+
client.auto_close_connection_pool = True
183+
return client
166184

167185
def __init__(
168186
self,
@@ -176,7 +194,6 @@ def __init__(
176194
socket_keepalive: Optional[bool] = None,
177195
socket_keepalive_options: Optional[Mapping[int, Union[int, bytes]]] = None,
178196
connection_pool: Optional[ConnectionPool] = None,
179-
from_pool: Optional[ConnectionPool] = None,
180197
unix_socket_path: Optional[str] = None,
181198
encoding: str = "utf-8",
182199
encoding_errors: str = "strict",
@@ -213,7 +230,7 @@ def __init__(
213230
"""
214231
kwargs: Dict[str, Any]
215232

216-
if not connection_pool and not from_pool:
233+
if not connection_pool:
217234
# Create internal connection pool, expected to be closed by Redis instance
218235
if not retry_on_error:
219236
retry_on_error = []
@@ -271,28 +288,14 @@ def __init__(
271288
"ssl_check_hostname": ssl_check_hostname,
272289
}
273290
)
274-
# backwards compatibility. This arg only used if no pool
275-
# is provided
276-
if auto_close_connection_pool:
277-
from_pool = ConnectionPool(**kwargs)
278-
else:
279-
connection_pool = ConnectionPool(**kwargs)
280-
281-
if from_pool is not None:
282-
# internal connection pool, expected to be closed by Redis instance
283-
if connection_pool is not None:
284-
raise ValueError(
285-
"Cannot use both from_pool and connection_pool arguments"
286-
)
287-
self.connection_pool = from_pool
288-
self.auto_close_connection_pool = True # the Redis instance closes the pool
291+
# This arg only used if no pool is passed in
292+
self.auto_close_connection_pool = auto_close_connection_pool
293+
connection_pool = ConnectionPool(**kwargs)
289294
else:
290-
# external connection pool, expected to be closed by caller
291-
self.connection_pool = connection_pool
292-
self.auto_close_connection_pool = (
293-
False # the user is expected to close the pool
294-
)
295+
# If a pool is passed in, do not close it
296+
self.auto_close_connection_pool = False
295297

298+
self.connection_pool = connection_pool
296299
self.single_connection_client = single_connection_client
297300
self.connection: Optional[Connection] = None
298301

redis/asyncio/connection.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1198,8 +1198,8 @@ class BlockingConnectionPool(ConnectionPool):
11981198
"""
11991199
Thread-safe blocking connection pool::
12001200
1201-
>>> from redis.client import Redis
1202-
>>> client = Redis(from_pool=BlockingConnectionPool())
1201+
>>> from redis.asyncio import Redis, BlockingConnectionPool
1202+
>>> client = Redis.from_pool(BlockingConnectionPool())
12031203
12041204
It performs the same function as the default
12051205
:py:class:`~redis.ConnectionPool` implementation, in that,

redis/asyncio/sentinel.py

+2-6
Original file line numberDiff line numberDiff line change
@@ -338,9 +338,7 @@ def master_for(
338338

339339
connection_pool = connection_pool_class(service_name, self, **connection_kwargs)
340340
# The Redis object "owns" the pool
341-
return redis_class(
342-
from_pool=connection_pool,
343-
)
341+
return redis_class.from_pool(connection_pool)
344342

345343
def slave_for(
346344
self,
@@ -372,6 +370,4 @@ def slave_for(
372370

373371
connection_pool = connection_pool_class(service_name, self, **connection_kwargs)
374372
# The Redis object "owns" the pool
375-
return redis_class(
376-
from_pool=connection_pool,
377-
)
373+
return redis_class.from_pool(connection_pool)

redis/client.py

+26-17
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import time
55
import warnings
66
from itertools import chain
7-
from typing import Optional
7+
from typing import Optional, Type
88

99
from redis._parsers.helpers import (
1010
_RedisCallbacks,
@@ -136,10 +136,28 @@ class initializer. In the case of conflicting arguments, querystring
136136
"""
137137
single_connection_client = kwargs.pop("single_connection_client", False)
138138
connection_pool = ConnectionPool.from_url(url, **kwargs)
139-
return cls(
140-
from_pool=connection_pool,
139+
client = cls(
140+
connection_pool=connection_pool,
141141
single_connection_client=single_connection_client,
142142
)
143+
client.auto_close_connection_pool = True
144+
return client
145+
146+
@classmethod
147+
def from_pool(
148+
cls: Type["Redis"],
149+
connection_pool: ConnectionPool,
150+
) -> "Redis":
151+
"""
152+
Return a Redis client from the given connection pool.
153+
The Redis client will take ownership of the connection pool and
154+
close it when the Redis client is closed.
155+
"""
156+
client = cls(
157+
connection_pool=connection_pool,
158+
)
159+
client.auto_close_connection_pool = True
160+
return client
143161

144162
def __init__(
145163
self,
@@ -152,7 +170,6 @@ def __init__(
152170
socket_keepalive=None,
153171
socket_keepalive_options=None,
154172
connection_pool=None,
155-
from_pool=None,
156173
unix_socket_path=None,
157174
encoding="utf-8",
158175
encoding_errors="strict",
@@ -199,7 +216,7 @@ def __init__(
199216
if `True`, connection pool is not used. In that case `Redis`
200217
instance use is not thread safe.
201218
"""
202-
if not connection_pool and not from_pool:
219+
if not connection_pool:
203220
if charset is not None:
204221
warnings.warn(
205222
DeprecationWarning(
@@ -275,20 +292,12 @@ def __init__(
275292
"ssl_ocsp_expected_cert": ssl_ocsp_expected_cert,
276293
}
277294
)
278-
from_pool = ConnectionPool(**kwargs)
279-
280-
if from_pool is not None:
281-
# internal connection pool, expected to be closed by Redis instance
282-
if connection_pool is not None:
283-
raise ValueError(
284-
"Cannot use both from_pool and connection_pool arguments")
285-
self.connection_pool = from_pool
286-
self.auto_close_connection_pool = True # the Redis instance closes the pool
295+
connection_pool = ConnectionPool(**kwargs)
296+
self.auto_close_connection_pool = True
287297
else:
288-
# external connection pool, expected to be closed by caller
289-
self.connection_pool = connection_pool
290-
self.auto_close_connection_pool = False # the user is expected to close the pool
298+
self.auto_close_connection_pool = False
291299

300+
self.connection_pool = connection_pool
292301
self.connection = None
293302
if single_connection_client:
294303
self.connection = self.connection_pool.get_connection("_")

redis/sentinel.py

+4-4
Original file line numberDiff line numberDiff line change
@@ -353,8 +353,8 @@ def master_for(
353353
kwargs["is_master"] = True
354354
connection_kwargs = dict(self.connection_kwargs)
355355
connection_kwargs.update(kwargs)
356-
return redis_class(
357-
from_pool=connection_pool_class(service_name, self, **connection_kwargs)
356+
return redis_class.from_pool(
357+
connection_pool_class(service_name, self, **connection_kwargs)
358358
)
359359

360360
def slave_for(
@@ -384,6 +384,6 @@ def slave_for(
384384
kwargs["is_master"] = False
385385
connection_kwargs = dict(self.connection_kwargs)
386386
connection_kwargs.update(kwargs)
387-
return redis_class(
388-
from_pool=connection_pool_class(service_name, self, **connection_kwargs)
387+
return redis_class.from_pool(
388+
connection_pool_class(service_name, self, **connection_kwargs)
389389
)

tests/test_asyncio/test_connection.py

+28-2
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ async def mock_disconnect(_):
356356

357357
@pytest.mark.parametrize("from_url", (True, False), ids=("from_url", "from_args"))
358358
async def test_redis_from_pool(request, from_url):
359-
"""Verify that basic Redis instances using `from_pool`
359+
"""Verify that basic Redis instances created using `from_pool()`
360360
have auto_close_connection_pool set to True"""
361361

362362
url: str = request.config.getoption("--redis-url")
@@ -370,7 +370,7 @@ async def get_redis_connection():
370370
pool = ConnectionPool.from_url(url)
371371
else:
372372
pool = ConnectionPool(**url_args)
373-
return Redis(from_pool=pool)
373+
return Redis.from_pool(pool)
374374

375375
called = 0
376376

@@ -384,3 +384,29 @@ async def mock_disconnect(_):
384384

385385
assert called == 1
386386
await pool.disconnect()
387+
388+
389+
@pytest.mark.parametrize("auto_close", (True, False))
390+
async def test_redis_pool_auto_close_arg(request, auto_close):
391+
"""test that redis instance where pool is provided have
392+
auto_close_connection_pool set to False, regardless of arg"""
393+
394+
url: str = request.config.getoption("--redis-url")
395+
pool = ConnectionPool.from_url(url)
396+
397+
async def get_redis_connection():
398+
client = Redis(connection_pool=pool, auto_close_connection_pool=auto_close)
399+
return client
400+
401+
called = 0
402+
403+
async def mock_disconnect(_):
404+
nonlocal called
405+
called += 1
406+
407+
with patch.object(ConnectionPool, "disconnect", mock_disconnect):
408+
async with await get_redis_connection() as r1:
409+
assert r1.auto_close_connection_pool is False
410+
411+
assert called == 0
412+
await pool.disconnect()

tests/test_connection.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ def mock_disconnect(_):
268268

269269
@pytest.mark.parametrize("from_url", (True, False), ids=("from_url", "from_args"))
270270
def test_redis_from_pool(request, from_url):
271-
"""Verify that basic Redis instances using `from_pool`
271+
"""Verify that basic Redis instances created using `from_pool()`
272272
have auto_close_connection_pool set to True"""
273273

274274
url: str = request.config.getoption("--redis-url")
@@ -282,7 +282,7 @@ def get_redis_connection():
282282
pool = ConnectionPool.from_url(url)
283283
else:
284284
pool = ConnectionPool(**url_args)
285-
return Redis(from_pool=pool)
285+
return Redis.from_pool(pool)
286286

287287
called = 0
288288

0 commit comments

Comments
 (0)