Skip to content

Commit f2df255

Browse files
committed
Implement DriverInfo pool propagation and deprecate lib_name/lib_version
1 parent 8ff83dc commit f2df255

File tree

8 files changed

+180
-48
lines changed

8 files changed

+180
-48
lines changed

redis/asyncio/client.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,11 @@ def from_pool(
215215
reason="TimeoutError is included by default.",
216216
version="6.0.0",
217217
)
218+
@deprecated_args(
219+
args_to_warn=["lib_name", "lib_version"],
220+
reason="Use 'driver_info' parameter instead. "
221+
"lib_name and lib_version will be removed in a future version.",
222+
)
218223
def __init__(
219224
self,
220225
*,
@@ -251,8 +256,8 @@ def __init__(
251256
single_connection_client: bool = False,
252257
health_check_interval: int = 0,
253258
client_name: Optional[str] = None,
254-
lib_name: Optional[str] = "redis-py",
255-
lib_version: Optional[str] = get_lib_version(),
259+
lib_name: Optional[str] = None,
260+
lib_version: Optional[str] = None,
256261
driver_info: Optional["DriverInfo"] = None,
257262
username: Optional[str] = None,
258263
auto_close_connection_pool: Optional[bool] = None,
@@ -306,10 +311,16 @@ def __init__(
306311
# Create internal connection pool, expected to be closed by Redis instance
307312
if not retry_on_error:
308313
retry_on_error = []
314+
315+
# Handle driver_info: if provided, use it; otherwise create from lib_name/lib_version
309316
if driver_info is not None:
310-
computed_lib_name = driver_info.formatted_name
317+
computed_driver_info = driver_info
311318
else:
312-
computed_lib_name = lib_name
319+
# Fallback: create DriverInfo from lib_name and lib_version
320+
# Use defaults if not provided
321+
name = lib_name if lib_name is not None else "redis-py"
322+
version = lib_version if lib_version is not None else get_lib_version()
323+
computed_driver_info = DriverInfo(name=name, lib_version=version)
313324

314325
kwargs = {
315326
"db": db,
@@ -325,8 +336,7 @@ def __init__(
325336
"max_connections": max_connections,
326337
"health_check_interval": health_check_interval,
327338
"client_name": client_name,
328-
"lib_name": computed_lib_name,
329-
"lib_version": lib_version,
339+
"driver_info": computed_driver_info,
330340
"redis_connect_func": redis_connect_func,
331341
"protocol": protocol,
332342
}

redis/asyncio/connection.py

Lines changed: 50 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
VerifyFlags = None
3939

4040
from ..auth.token import TokenInterface
41+
from ..driver_info import DriverInfo
4142
from ..event import AsyncAfterConnectionReleasedEvent, EventDispatcher
4243
from ..utils import deprecated_args, format_error_message
4344

@@ -137,6 +138,11 @@ class AbstractConnection:
137138
"__dict__",
138139
)
139140

141+
@deprecated_args(
142+
args_to_warn=["lib_name", "lib_version"],
143+
reason="Use 'driver_info' parameter instead. "
144+
"lib_name and lib_version will be removed in a future version.",
145+
)
140146
def __init__(
141147
self,
142148
*,
@@ -153,8 +159,9 @@ def __init__(
153159
socket_read_size: int = 65536,
154160
health_check_interval: float = 0,
155161
client_name: Optional[str] = None,
156-
lib_name: Optional[str] = "redis-py",
157-
lib_version: Optional[str] = get_lib_version(),
162+
lib_name: Optional[str] = None,
163+
lib_version: Optional[str] = None,
164+
driver_info: Optional[DriverInfo] = None,
158165
username: Optional[str] = None,
159166
retry: Optional[Retry] = None,
160167
redis_connect_func: Optional[ConnectCallbackT] = None,
@@ -163,6 +170,20 @@ def __init__(
163170
protocol: Optional[int] = 2,
164171
event_dispatcher: Optional[EventDispatcher] = None,
165172
):
173+
"""
174+
Initialize a new async Connection.
175+
176+
Parameters
177+
----------
178+
driver_info : DriverInfo, optional
179+
Driver metadata for CLIENT SETINFO. If provided, lib_name and lib_version
180+
are ignored. If not provided, a DriverInfo will be created from lib_name
181+
and lib_version (or defaults if those are also None).
182+
lib_name : str, optional
183+
**Deprecated.** Use driver_info instead. Library name for CLIENT SETINFO.
184+
lib_version : str, optional
185+
**Deprecated.** Use driver_info instead. Library version for CLIENT SETINFO.
186+
"""
166187
if (username or password) and credential_provider is not None:
167188
raise DataError(
168189
"'username' and 'password' cannot be passed along with 'credential_"
@@ -176,8 +197,17 @@ def __init__(
176197
self._event_dispatcher = event_dispatcher
177198
self.db = db
178199
self.client_name = client_name
179-
self.lib_name = lib_name
180-
self.lib_version = lib_version
200+
201+
# Handle driver_info: if provided, use it; otherwise create from lib_name/lib_version
202+
if driver_info is not None:
203+
self.driver_info = driver_info
204+
else:
205+
# Fallback: create DriverInfo from lib_name and lib_version
206+
# Use defaults if not provided
207+
name = lib_name if lib_name is not None else "redis-py"
208+
version = lib_version if lib_version is not None else get_lib_version()
209+
self.driver_info = DriverInfo(name=name, lib_version=version)
210+
181211
self.credential_provider = credential_provider
182212
self.password = password
183213
self.username = username
@@ -452,29 +482,36 @@ async def on_connect_check_health(self, check_health: bool = True) -> None:
452482
if str_if_bytes(await self.read_response()) != "OK":
453483
raise ConnectionError("Error setting client name")
454484

455-
# set the library name and version, pipeline for lower startup latency
456-
if self.lib_name:
485+
# Set the library name and version from driver_info, pipeline for lower startup latency
486+
lib_name_sent = False
487+
lib_version_sent = False
488+
489+
if self.driver_info and self.driver_info.formatted_name:
457490
await self.send_command(
458491
"CLIENT",
459492
"SETINFO",
460493
"LIB-NAME",
461-
self.lib_name,
494+
self.driver_info.formatted_name,
462495
check_health=check_health,
463496
)
464-
if self.lib_version:
497+
lib_name_sent = True
498+
499+
if self.driver_info and self.driver_info.lib_version:
465500
await self.send_command(
466501
"CLIENT",
467502
"SETINFO",
468503
"LIB-VER",
469-
self.lib_version,
504+
self.driver_info.lib_version,
470505
check_health=check_health,
471506
)
507+
lib_version_sent = True
508+
472509
# if a database is specified, switch to it. Also pipeline this
473510
if self.db:
474511
await self.send_command("SELECT", self.db, check_health=check_health)
475512

476513
# read responses from pipeline
477-
for _ in (sent for sent in (self.lib_name, self.lib_version) if sent):
514+
for _ in range(sum([lib_name_sent, lib_version_sent])):
478515
try:
479516
await self.read_response()
480517
except ResponseError:
@@ -1174,6 +1211,9 @@ def __init__(
11741211
if self._event_dispatcher is None:
11751212
self._event_dispatcher = EventDispatcher()
11761213

1214+
# Store driver_info for propagation to connections
1215+
self.driver_info = self.connection_kwargs.get("driver_info", None)
1216+
11771217
def __repr__(self):
11781218
conn_kwargs = ",".join([f"{k}={v}" for k, v in self.connection_kwargs.items()])
11791219
return (

redis/client.py

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ def from_pool(
200200
reason="TimeoutError is included by default.",
201201
version="6.0.0",
202202
)
203+
@deprecated_args(
204+
args_to_warn=["lib_name", "lib_version"],
205+
reason="Use 'driver_info' parameter instead. "
206+
"lib_name and lib_version will be removed in a future version.",
207+
)
203208
def __init__(
204209
self,
205210
host: str = "localhost",
@@ -241,8 +246,8 @@ def __init__(
241246
single_connection_client: bool = False,
242247
health_check_interval: int = 0,
243248
client_name: Optional[str] = None,
244-
lib_name: Optional[str] = "redis-py",
245-
lib_version: Optional[str] = get_lib_version(),
249+
lib_name: Optional[str] = None,
250+
lib_version: Optional[str] = None,
246251
driver_info: Optional["DriverInfo"] = None,
247252
username: Optional[str] = None,
248253
redis_connect_func: Optional[Callable[[], None]] = None,
@@ -284,7 +289,13 @@ def __init__(
284289
Argument is ignored when connection_pool is provided.
285290
driver_info:
286291
Optional DriverInfo object to identify upstream libraries.
292+
If provided, lib_name and lib_version are ignored.
293+
If not provided, a DriverInfo will be created from lib_name and lib_version.
287294
Argument is ignored when connection_pool is provided.
295+
lib_name:
296+
**Deprecated.** Use driver_info instead. Library name for CLIENT SETINFO.
297+
lib_version:
298+
**Deprecated.** Use driver_info instead. Library version for CLIENT SETINFO.
288299
maint_notifications_config:
289300
configuration the pool to support maintenance notifications - see
290301
`redis.maint_notifications.MaintNotificationsConfig` for details.
@@ -301,10 +312,16 @@ def __init__(
301312
if not connection_pool:
302313
if not retry_on_error:
303314
retry_on_error = []
315+
316+
# Handle driver_info: if provided, use it; otherwise create from lib_name/lib_version
304317
if driver_info is not None:
305-
computed_lib_name = driver_info.formatted_name
318+
computed_driver_info = driver_info
306319
else:
307-
computed_lib_name = lib_name
320+
# Fallback: create DriverInfo from lib_name and lib_version
321+
# Use defaults if not provided
322+
name = lib_name if lib_name is not None else "redis-py"
323+
version = lib_version if lib_version is not None else get_lib_version()
324+
computed_driver_info = DriverInfo(name=name, lib_version=version)
308325

309326
kwargs = {
310327
"db": db,
@@ -319,8 +336,7 @@ def __init__(
319336
"max_connections": max_connections,
320337
"health_check_interval": health_check_interval,
321338
"client_name": client_name,
322-
"lib_name": computed_lib_name,
323-
"lib_version": lib_version,
339+
"driver_info": computed_driver_info,
324340
"redis_connect_func": redis_connect_func,
325341
"credential_provider": credential_provider,
326342
"protocol": protocol,

redis/connection.py

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535
from .auth.token import TokenInterface
3636
from .backoff import NoBackoff
3737
from .credentials import CredentialProvider, UsernamePasswordCredentialProvider
38+
from .driver_info import DriverInfo
3839
from .event import AfterConnectionReleasedEvent, EventDispatcher
3940
from .exceptions import (
4041
AuthenticationError,
@@ -655,6 +656,11 @@ def reset_tmp_settings(
655656
class AbstractConnection(MaintNotificationsAbstractConnection, ConnectionInterface):
656657
"Manages communication to and from a Redis server"
657658

659+
@deprecated_args(
660+
args_to_warn=["lib_name", "lib_version"],
661+
reason="Use 'driver_info' parameter instead. "
662+
"lib_name and lib_version will be removed in a future version.",
663+
)
658664
def __init__(
659665
self,
660666
db: int = 0,
@@ -670,8 +676,9 @@ def __init__(
670676
socket_read_size: int = 65536,
671677
health_check_interval: int = 0,
672678
client_name: Optional[str] = None,
673-
lib_name: Optional[str] = "redis-py",
674-
lib_version: Optional[str] = get_lib_version(),
679+
lib_name: Optional[str] = None,
680+
lib_version: Optional[str] = None,
681+
driver_info: Optional[DriverInfo] = None,
675682
username: Optional[str] = None,
676683
retry: Union[Any, None] = None,
677684
redis_connect_func: Optional[Callable[[], None]] = None,
@@ -691,10 +698,22 @@ def __init__(
691698
):
692699
"""
693700
Initialize a new Connection.
701+
694702
To specify a retry policy for specific errors, first set
695703
`retry_on_error` to a list of the error/s to retry on, then set
696704
`retry` to a valid `Retry` object.
697705
To retry on TimeoutError, `retry_on_timeout` can also be set to `True`.
706+
707+
Parameters
708+
----------
709+
driver_info : DriverInfo, optional
710+
Driver metadata for CLIENT SETINFO. If provided, lib_name and lib_version
711+
are ignored. If not provided, a DriverInfo will be created from lib_name
712+
and lib_version (or defaults if those are also None).
713+
lib_name : str, optional
714+
**Deprecated.** Use driver_info instead. Library name for CLIENT SETINFO.
715+
lib_version : str, optional
716+
**Deprecated.** Use driver_info instead. Library version for CLIENT SETINFO.
698717
"""
699718
if (username or password) and credential_provider is not None:
700719
raise DataError(
@@ -710,8 +729,17 @@ def __init__(
710729
self.pid = os.getpid()
711730
self.db = db
712731
self.client_name = client_name
713-
self.lib_name = lib_name
714-
self.lib_version = lib_version
732+
733+
# Handle driver_info: if provided, use it; otherwise create from lib_name/lib_version
734+
if driver_info is not None:
735+
self.driver_info = driver_info
736+
else:
737+
# Fallback: create DriverInfo from lib_name and lib_version
738+
# Use defaults if not provided
739+
name = lib_name if lib_name is not None else "redis-py"
740+
version = lib_version if lib_version is not None else get_lib_version()
741+
self.driver_info = DriverInfo(name=name, lib_version=version)
742+
715743
self.credential_provider = credential_provider
716744
self.password = password
717745
self.username = username
@@ -988,27 +1016,27 @@ def on_connect_check_health(self, check_health: bool = True):
9881016
if str_if_bytes(self.read_response()) != "OK":
9891017
raise ConnectionError("Error setting client name")
9901018

1019+
# Set the library name and version from driver_info
9911020
try:
992-
# set the library name and version
993-
if self.lib_name:
1021+
if self.driver_info and self.driver_info.formatted_name:
9941022
self.send_command(
9951023
"CLIENT",
9961024
"SETINFO",
9971025
"LIB-NAME",
998-
self.lib_name,
1026+
self.driver_info.formatted_name,
9991027
check_health=check_health,
10001028
)
10011029
self.read_response()
10021030
except ResponseError:
10031031
pass
10041032

10051033
try:
1006-
if self.lib_version:
1034+
if self.driver_info and self.driver_info.lib_version:
10071035
self.send_command(
10081036
"CLIENT",
10091037
"SETINFO",
10101038
"LIB-VER",
1011-
self.lib_version,
1039+
self.driver_info.lib_version,
10121040
check_health=check_health,
10131041
)
10141042
self.read_response()
@@ -2482,6 +2510,9 @@ def __init__(
24822510
if self._event_dispatcher is None:
24832511
self._event_dispatcher = EventDispatcher()
24842512

2513+
# Store driver_info for propagation to connections
2514+
self.driver_info = self._connection_kwargs.get("driver_info", None)
2515+
24852516
# a lock to protect the critical section in _checkpid().
24862517
# this lock is acquired when the process id changes, such as
24872518
# after a fork. during this time, multiple threads in the child

0 commit comments

Comments
 (0)