Repository: redis/redis-py

Issue:
Unexpected keyword argument 'retry' when using unix socket
**redis-py 3.9.9, redis 6.2.6**

When I tried to use unix socket connection:
```
db = Redis(unix_socket_path='/run/redis/.sock')
db.info()
```
I got error:
```
   1196             raise ConnectionError("Too many connections")
   1197         self._created_connections += 1
-> 1198         return self.connection_class(**self.connection_kwargs)
   1199 
   1200     def release(self, connection):

TypeError: __init__() got an unexpected keyword argument 'retry'
```
almost same using UnixDomainSocketConnection:
```
pool = redis.ConnectionPool(connection_class=redis.UnixDomainSocketConnection, path='/tmp/.sock')
db = redis.Redis(connection_pool=pool)
```
```
   1035         try:
-> 1036             return conn.retry.call_with_retry(
   1037                 lambda: self._send_command_parse_response(conn,
   1038                                                           command_name,

AttributeError: 'UnixDomainSocketConnection' object has no attribute 'retry'
```


Discussion:
Looking


Resolving patch:
diff --git a/redis/connection.py b/redis/connection.py
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -880,7 +880,13 @@ def __init__(self, path='', db=0, username=None, password=None,
                  encoding_errors='strict', decode_responses=False,
                  retry_on_timeout=False,
                  parser_class=DefaultParser, socket_read_size=65536,
-                 health_check_interval=0, client_name=None):
+                 health_check_interval=0, client_name=None,
+                 retry=None):
+        """
+        Initialize a new UnixDomainSocketConnection.
+        To specify a retry policy, first set `retry_on_timeout` to `True`
+        then set `retry` to a valid `Retry` object
+        """
         self.pid = os.getpid()
         self.path = path
         self.db = db
@@ -889,6 +895,14 @@ def __init__(self, path='', db=0, username=None, password=None,
         self.password = password
         self.socket_timeout = socket_timeout
         self.retry_on_timeout = retry_on_timeout
+        if retry_on_timeout:
+            if retry is None:
+                self.retry = Retry(NoBackoff(), 1)
+            else:
+                # deep-copy the Retry object as it is mutable
+                self.retry = copy.deepcopy(retry)
+        else:
+            self.retry = Retry(NoBackoff(), 0)
         self.health_check_interval = health_check_interval
         self.next_health_check = 0
         self.encoder = Encoder(encoding, encoding_errors, decode_responses)


Test patch:
diff --git a/tests/test_retry.py b/tests/test_retry.py
--- a/tests/test_retry.py
+++ b/tests/test_retry.py
@@ -2,7 +2,7 @@
 import pytest
 
 from redis.exceptions import ConnectionError
-from redis.connection import Connection
+from redis.connection import Connection, UnixDomainSocketConnection
 from redis.retry import Retry
 
 
@@ -20,20 +20,22 @@ def compute(self, failures):
 
 
 class TestConnectionConstructorWithRetry:
-    "Test that the Connection constructor properly handles Retry objects"
+    "Test that the Connection constructors properly handles Retry objects"
 
     @pytest.mark.parametrize("retry_on_timeout", [False, True])
-    def test_retry_on_timeout_boolean(self, retry_on_timeout):
-        c = Connection(retry_on_timeout=retry_on_timeout)
+    @pytest.mark.parametrize("Class", [Connection, UnixDomainSocketConnection])
+    def test_retry_on_timeout_boolean(self, Class, retry_on_timeout):
+        c = Class(retry_on_timeout=retry_on_timeout)
         assert c.retry_on_timeout == retry_on_timeout
         assert isinstance(c.retry, Retry)
         assert c.retry._retries == (1 if retry_on_timeout else 0)
 
     @pytest.mark.parametrize("retries", range(10))
-    def test_retry_on_timeout_retry(self, retries):
+    @pytest.mark.parametrize("Class", [Connection, UnixDomainSocketConnection])
+    def test_retry_on_timeout_retry(self, Class, retries):
         retry_on_timeout = retries > 0
-        c = Connection(retry_on_timeout=retry_on_timeout,
-                       retry=Retry(NoBackoff(), retries))
+        c = Class(retry_on_timeout=retry_on_timeout,
+                  retry=Retry(NoBackoff(), retries))
         assert c.retry_on_timeout == retry_on_timeout
         assert isinstance(c.retry, Retry)
         assert c.retry._retries == retries