Repository: redis/redis-py

Issue:
Unable to install with hiredis option
pip install redis[hiredis] return "no matches found: redis[hiredis]"

python version 3.8

pip install redis and pip install hiredis work



Discussion:

Patch:
diff --git a/README.md b/README.md
index c02483f..6b53b42 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,7 @@ For faster performance, install redis with hiredis support, this provides a comp
 By default, if hiredis >= 1.0 is available, redis-py will attempt to use it for response parsing.
 
 ``` bash
-$ pip install redis[hiredis]
+$ pip install "redis[hiredis]"
 ```
 
 Looking for a high-level library to handle object mapping? See [redis-om-python](https://github.com/redis/redis-om-python)!
diff --git a/redis/commands/core.py b/redis/commands/core.py
index b07f12d..28dab81 100644
--- a/redis/commands/core.py
+++ b/redis/commands/core.py
@@ -2667,7 +2667,11 @@ class ListCommands(CommandsProtocol):
         """
         return self.execute_command("LLEN", name)
 
-    def lpop(self, name: str, count: Optional[int] = None) -> Union[str, List, None]:
+    def lpop(
+        self,
+        name: str,
+        count: Optional[int] = None,
+    ) -> Union[Awaitable[Union[str, List, None]], Union[str, List, None]]:
         """
         Removes and returns the first elements of the list ``name``.
 
@@ -2744,7 +2748,11 @@ class ListCommands(CommandsProtocol):
         """
         return self.execute_command("LTRIM", name, start, end)
 
-    def rpop(self, name: str, count: Optional[int] = None) -> Union[str, List, None]:
+    def rpop(
+        self,
+        name: str,
+        count: Optional[int] = None,
+    ) -> Union[Awaitable[Union[str, List, None]], Union[str, List, None]]:
         """
         Removes and returns the last elements of the list ``name``.
 
diff --git a/redis/connection.py b/redis/connection.py
index 2461482..d35980c 100644
--- a/redis/connection.py
+++ b/redis/connection.py
@@ -1153,6 +1153,7 @@ class UnixDomainSocketConnection(Connection):
         retry=None,
         redis_connect_func=None,
         credential_provider: Optional[CredentialProvider] = None,
+        command_packer=None,
     ):
         """
         Initialize a new UnixDomainSocketConnection.
@@ -1202,6 +1203,7 @@ class UnixDomainSocketConnection(Connection):
         self.set_parser(parser_class)
         self._connect_callbacks = []
         self._buffer_cutoff = 6000
+        self._command_packer = self._construct_command_packer(command_packer)
 
     def repr_pieces(self):
         pieces = [("path", self.path), ("db", self.db)]
diff --git a/setup.py b/setup.py
index 022a27e..060e9da 100644
--- a/setup.py
+++ b/setup.py
@@ -8,7 +8,7 @@ setup(
     long_description_content_type="text/markdown",
     keywords=["Redis", "key-value store", "database"],
     license="MIT",
-    version="4.5.0",
+    version="4.5.1",
     packages=find_packages(
         include=[
             "redis",


Test patch:
diff --git a/tests/test_connection.py b/tests/test_connection.py
index e0b53cd..25b4118 100644
--- a/tests/test_connection.py
+++ b/tests/test_connection.py
@@ -7,7 +7,13 @@ import pytest
 
 import redis
 from redis.backoff import NoBackoff
-from redis.connection import Connection, HiredisParser, PythonParser
+from redis.connection import (
+    Connection,
+    HiredisParser,
+    PythonParser,
+    SSLConnection,
+    UnixDomainSocketConnection,
+)
 from redis.exceptions import ConnectionError, InvalidResponse, TimeoutError
 from redis.retry import Retry
 from redis.utils import HIREDIS_AVAILABLE
@@ -163,3 +169,39 @@ def test_connection_parse_response_resume(r: redis.Redis, parser_class):
         pytest.fail("didn't receive a response")
     assert response
     assert i > 0
+
+
+@pytest.mark.onlynoncluster
+@pytest.mark.parametrize(
+    "Class",
+    [
+        Connection,
+        SSLConnection,
+        UnixDomainSocketConnection,
+    ],
+)
+def test_pack_command(Class):
+    """
+    This test verifies that the pack_command works
+    on all supported connections. #2581
+    """
+    cmd = (
+        "HSET",
+        "foo",
+        "key",
+        "value1",
+        b"key_b",
+        b"bytes str",
+        b"key_i",
+        67,
+        "key_f",
+        3.14159265359,
+    )
+    expected = (
+        b"*10\r\n$4\r\nHSET\r\n$3\r\nfoo\r\n$3\r\nkey\r\n$6\r\nvalue1\r\n"
+        b"$5\r\nkey_b\r\n$9\r\nbytes str\r\n$5\r\nkey_i\r\n$2\r\n67\r\n$5"
+        b"\r\nkey_f\r\n$13\r\n3.14159265359\r\n"
+    )
+
+    actual = Class().pack_command(*cmd)[0]
+    assert actual == expected, f"actual = {actual}, expected = {expected}"