Skip to content

Commit

Permalink
Support Hiredis >= 1.x only (remove packaging dependency) (redis#2385)
Browse files Browse the repository at this point in the history
* Only set HIREDIS_AVAILABLE if Hiredis is not 0.x

* Remove compatibility code for old Hiredis versions

* Move packaging dependency to dev only
  • Loading branch information
akx authored Sep 28, 2022
1 parent 947b8e8 commit 027abe5
Show file tree
Hide file tree
Showing 7 changed files with 16 additions and 48 deletions.
1 change: 1 addition & 0 deletions CHANGES
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
* Fix reusing the old nodes' connections when cluster topology refresh is being done
* Fix RedisCluster to immediately raise AuthenticationError without a retry
* ClusterPipeline Doesn't Handle ConnectionError for Dead Hosts (#2225)
* Remove compatibility code for old versions of Hiredis, drop Packaging dependency

* 4.1.3 (Feb 8, 2022)
* Fix flushdb and flushall (#1926)
Expand Down
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ To install redis-py, simply:
$ pip install redis
```

For faster performance, install redis with hiredis support, this provides a compiled response parser, and *for most cases* requires zero code changes. By default, if hiredis is available, redis-py will attempt to use it for response parsing.
For faster performance, install redis with hiredis support, this provides a compiled response parser, and *for most cases* requires zero code changes.
By default, if hiredis >= 1.0 is available, redis-py will attempt to use it for response parsing.

``` bash
$ pip install redis[hiredis]
Expand Down
1 change: 1 addition & 0 deletions dev_requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ flake8==4.0.1
flynt~=0.69.0
isort==5.10.1
mock==4.0.3
packaging>=20.4
pytest==6.2.5
pytest-timeout==2.0.1
pytest-asyncio>=0.16.0
Expand Down
54 changes: 10 additions & 44 deletions redis/connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,6 @@
from time import time
from urllib.parse import parse_qs, unquote, urlparse

from packaging.version import Version

from redis.backoff import NoBackoff
from redis.exceptions import (
AuthenticationError,
Expand Down Expand Up @@ -54,16 +52,6 @@
if HIREDIS_AVAILABLE:
import hiredis

hiredis_version = Version(hiredis.__version__)
HIREDIS_SUPPORTS_CALLABLE_ERRORS = hiredis_version >= Version("0.1.3")
HIREDIS_SUPPORTS_BYTE_BUFFER = hiredis_version >= Version("0.1.4")
HIREDIS_SUPPORTS_ENCODING_ERRORS = hiredis_version >= Version("1.0.0")

HIREDIS_USE_BYTE_BUFFER = True
# only use byte buffer if hiredis supports it
if not HIREDIS_SUPPORTS_BYTE_BUFFER:
HIREDIS_USE_BYTE_BUFFER = False

SYM_STAR = b"*"
SYM_DOLLAR = b"$"
SYM_CRLF = b"\r\n"
Expand Down Expand Up @@ -380,9 +368,7 @@ def __init__(self, socket_read_size):
if not HIREDIS_AVAILABLE:
raise RedisError("Hiredis is not installed")
self.socket_read_size = socket_read_size

if HIREDIS_USE_BYTE_BUFFER:
self._buffer = bytearray(socket_read_size)
self._buffer = bytearray(socket_read_size)

def __del__(self):
try:
Expand All @@ -393,16 +379,14 @@ def __del__(self):
def on_connect(self, connection, **kwargs):
self._sock = connection._sock
self._socket_timeout = connection.socket_timeout
kwargs = {"protocolError": InvalidResponse, "replyError": self.parse_error}

# hiredis < 0.1.3 doesn't support functions that create exceptions
if not HIREDIS_SUPPORTS_CALLABLE_ERRORS:
kwargs["replyError"] = ResponseError
kwargs = {
"protocolError": InvalidResponse,
"replyError": self.parse_error,
"errors": connection.encoder.encoding_errors,
}

if connection.encoder.decode_responses:
kwargs["encoding"] = connection.encoder.encoding
if HIREDIS_SUPPORTS_ENCODING_ERRORS:
kwargs["errors"] = connection.encoder.encoding_errors
self._reader = hiredis.Reader(**kwargs)
self._next_response = False

Expand All @@ -427,17 +411,10 @@ def read_from_socket(self, timeout=SENTINEL, raise_on_timeout=True):
try:
if custom_timeout:
sock.settimeout(timeout)
if HIREDIS_USE_BYTE_BUFFER:
bufflen = self._sock.recv_into(self._buffer)
if bufflen == 0:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
self._reader.feed(self._buffer, 0, bufflen)
else:
buffer = self._sock.recv(self.socket_read_size)
# an empty string indicates the server shutdown the socket
if not isinstance(buffer, bytes) or len(buffer) == 0:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
self._reader.feed(buffer)
bufflen = self._sock.recv_into(self._buffer)
if bufflen == 0:
raise ConnectionError(SERVER_CLOSED_CONNECTION_ERROR)
self._reader.feed(self._buffer, 0, bufflen)
# data was read from the socket and added to the buffer.
# return True to indicate that data was read.
return True
Expand Down Expand Up @@ -479,17 +456,6 @@ def read_response(self, disable_decoding=False):
response = self._reader.gets(False)
else:
response = self._reader.gets()
# if an older version of hiredis is installed, we need to attempt
# to convert ResponseErrors to their appropriate types.
if not HIREDIS_SUPPORTS_CALLABLE_ERRORS:
if isinstance(response, ResponseError):
response = self.parse_error(response.args[0])
elif (
isinstance(response, list)
and response
and isinstance(response[0], ResponseError)
):
response[0] = self.parse_error(response[0].args[0])
# if the response is a ConnectionError or the response is a list and
# the first item is a ConnectionError, raise it as something bad
# happened
Expand Down
3 changes: 2 additions & 1 deletion redis/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@
try:
import hiredis # noqa

HIREDIS_AVAILABLE = True
# Only support Hiredis >= 1.0:
HIREDIS_AVAILABLE = not hiredis.__version__.startswith("0.")
except ImportError:
HIREDIS_AVAILABLE = False

Expand Down
1 change: 0 additions & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
async-timeout>=4.0.2
deprecated>=1.2.3
packaging>=20.4
typing-extensions; python_version<"3.8"
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
python_requires=">=3.7",
install_requires=[
"deprecated>=1.2.3",
"packaging>=20.4",
'importlib-metadata >= 1.0; python_version < "3.8"',
'typing-extensions; python_version<"3.8"',
"async-timeout>=4.0.2",
Expand Down

0 comments on commit 027abe5

Please sign in to comment.