From 176831943cc206c47f75c4a93f1dd41bcd7591f4 Mon Sep 17 00:00:00 2001 From: Mikhail Koviazin Date: Wed, 3 Jul 2024 15:59:28 +0300 Subject: [PATCH] Replace hiredis dependency with valkey Signed-off-by: Mikhail Koviazin --- .github/wordlist.txt | 2 +- .github/workflows/integration.yaml | 14 ++++----- README.md | 6 ++-- benchmarks/socket_read_size.py | 4 +-- setup.py | 2 +- tasks.py | 2 +- tests/test_asyncio/test_bloom.py | 4 +-- tests/test_asyncio/test_cache.py | 8 ++--- tests/test_asyncio/test_connection.py | 18 +++++------ tests/test_asyncio/test_pubsub.py | 6 ++-- tests/test_bloom.py | 4 +-- tests/test_cache.py | 10 +++--- tests/test_command_parser.py | 6 ++-- tests/test_commands.py | 6 ++-- tests/test_connection.py | 16 +++++----- tests/test_encoding.py | 6 ++-- tests/test_pubsub.py | 8 ++--- valkey/_parsers/__init__.py | 6 ++-- valkey/_parsers/{hiredis.py => libvalkey.py} | 32 ++++++++++---------- valkey/asyncio/client.py | 4 +-- valkey/asyncio/connection.py | 14 ++++----- valkey/client.py | 4 +-- valkey/cluster.py | 4 +-- valkey/commands/bf/commands.py | 8 +++-- valkey/connection.py | 26 ++++++++-------- valkey/utils.py | 12 ++++---- 26 files changed, 117 insertions(+), 115 deletions(-) rename valkey/_parsers/{hiredis.py => libvalkey.py} (91%) diff --git a/.github/wordlist.txt b/.github/wordlist.txt index 2b4b87de..cd68dcab 100644 --- a/.github/wordlist.txt +++ b/.github/wordlist.txt @@ -89,7 +89,6 @@ firsttimersonly fo genindex gmail -hiredis html http https @@ -101,6 +100,7 @@ json keyslot keyspace kwarg +libvalkey linters localhost lua diff --git a/.github/workflows/integration.yaml b/.github/workflows/integration.yaml index 3ea5fbb2..1bcab5aa 100644 --- a/.github/workflows/integration.yaml +++ b/.github/workflows/integration.yaml @@ -59,7 +59,7 @@ jobs: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.9', 'pypy-3.10'] test-type: ['standalone', 'cluster'] - connection-type: ['hiredis', 'plain'] + connection-type: ['libvalkey', 'plain'] env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true name: Python ${{ matrix.python-version }} ${{matrix.test-type}}-${{matrix.connection-type}} tests @@ -74,8 +74,8 @@ jobs: pip install -U setuptools wheel pip install -r requirements.txt pip install -r dev_requirements.txt - if [ "${{matrix.connection-type}}" == "hiredis" ]; then - pip install "hiredis<3.0.0" + if [ "${{matrix.connection-type}}" == "libvalkey" ]; then + pip install libvalkey fi invoke devenv sleep 10 # time to settle @@ -104,10 +104,10 @@ jobs: matrix: python-version: ['3.8', '3.9', '3.10', '3.11', '3.12', 'pypy-3.9', 'pypy-3.10'] test-type: ['standalone', 'cluster'] - connection-type: ['hiredis', 'plain'] + connection-type: ['libvalkey', 'plain'] exclude: - test-type: 'cluster' - connection-type: 'hiredis' + connection-type: 'libvalkey' env: ACTIONS_ALLOW_UNSECURE_COMMANDS: true name: RESP3 [${{ matrix.python-version }} ${{matrix.test-type}}-${{matrix.connection-type}}] @@ -122,8 +122,8 @@ jobs: pip install -U setuptools wheel pip install -r requirements.txt pip install -r dev_requirements.txt - if [ "${{matrix.connection-type}}" == "hiredis" ]; then - pip install "hiredis<3.0.0" + if [ "${{matrix.connection-type}}" == "libvalkey" ]; then + pip install libvalkey fi invoke devenv sleep 10 # time to settle diff --git a/README.md b/README.md index ddc30c6e..a900d23d 100644 --- a/README.md +++ b/README.md @@ -27,11 +27,11 @@ To install valkey-py, simply: $ pip install valkey ``` -For faster performance, install valkey 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, valkey-py will attempt to use it for response parsing. +For faster performance, install valkey with libvalkey support, this provides a compiled response parser, and *for most cases* requires zero code changes. +By default, if libvalkey >= 2.3.2 is available, valkey-py will attempt to use it for response parsing. ``` bash -$ pip install "valkey[hiredis]" +$ pip install "valkey[libvalkey]" ``` ## Usage diff --git a/benchmarks/socket_read_size.py b/benchmarks/socket_read_size.py index cc7c943b..6d59ad38 100644 --- a/benchmarks/socket_read_size.py +++ b/benchmarks/socket_read_size.py @@ -1,12 +1,12 @@ from base import Benchmark -from valkey.connection import PythonParser, _HiredisParser +from valkey.connection import PythonParser, _LibvalkeyParser class SocketReadBenchmark(Benchmark): ARGUMENTS = ( - {"name": "parser", "values": [PythonParser, _HiredisParser]}, + {"name": "parser", "values": [PythonParser, _LibvalkeyParser]}, { "name": "value_size", "values": [10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000], diff --git a/setup.py b/setup.py index 54ad4a50..fc3402cf 100644 --- a/setup.py +++ b/setup.py @@ -55,7 +55,7 @@ "Programming Language :: Python :: Implementation :: PyPy", ], extras_require={ - "hiredis": ["hiredis >=1.0.0, <3.0.0"], + "libvalkey": ["libvalkey>=3.0.0"], "ocsp": ["cryptography>=36.0.1", "pyopenssl==20.0.1", "requests>=2.26.0"], }, ) diff --git a/tasks.py b/tasks.py index ff1466bc..669a529f 100644 --- a/tasks.py +++ b/tasks.py @@ -44,7 +44,7 @@ def all_tests(c, color=False): @task def tests(c, uvloop=False, protocol=2, color=False): """Run the valkey-py test suite against the current python, - with and without hiredis. + with and without libvalkey. """ print("Starting Valkey tests") standalone_tests(c, uvloop=uvloop, protocol=protocol, color=color) diff --git a/tests/test_asyncio/test_bloom.py b/tests/test_asyncio/test_bloom.py index b19f3d24..01a071f6 100644 --- a/tests/test_asyncio/test_bloom.py +++ b/tests/test_asyncio/test_bloom.py @@ -8,7 +8,7 @@ skip_ifmodversion_lt, ) from valkey.exceptions import ModuleError, ValkeyError -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE pytestmark = pytest.mark.skip @@ -96,7 +96,7 @@ async def do_verify(): await do_verify() cmds = [] - if HIREDIS_AVAILABLE: + if LIBVALKEY_AVAILABLE: with pytest.raises(ModuleError): cur = await decoded_r.bf().scandump("myBloom", 0) return diff --git a/tests/test_asyncio/test_cache.py b/tests/test_asyncio/test_cache.py index 13092a23..df8ea110 100644 --- a/tests/test_asyncio/test_cache.py +++ b/tests/test_asyncio/test_cache.py @@ -3,7 +3,7 @@ import pytest import pytest_asyncio from valkey._cache import EvictionPolicy, _LocalCache -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE @pytest_asyncio.fixture @@ -19,7 +19,7 @@ async def local_cache(): yield _LocalCache() -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") class TestLocalCache: @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) @pytest.mark.onlynoncluster @@ -299,7 +299,7 @@ async def test_flush_entire_cache(self, r): assert await r.get("c") == "1" -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlycluster class TestClusterLocalCache: @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) @@ -368,7 +368,7 @@ async def test_execute_command_keys_not_provided(self, r): assert cache.get(("GET", "b")) is None -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlynoncluster class TestSentinelLocalCache: diff --git a/tests/test_asyncio/test_connection.py b/tests/test_asyncio/test_connection.py index 6851cfda..d9a2dfd1 100644 --- a/tests/test_asyncio/test_connection.py +++ b/tests/test_asyncio/test_connection.py @@ -7,7 +7,7 @@ import valkey from tests.conftest import skip_if_server_version_lt from valkey._parsers import ( - _AsyncHiredisParser, + _AsyncLibvalkeyParser, _AsyncRESP2Parser, _AsyncRESP3Parser, _AsyncRESPBase, @@ -18,7 +18,7 @@ from valkey.asyncio.retry import Retry from valkey.backoff import NoBackoff from valkey.exceptions import ConnectionError, InvalidResponse, TimeoutError -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .compat import mock from .mocks import MockStream @@ -177,7 +177,7 @@ async def test_connect_timeout_error_without_retry(): async def test_connection_parse_response_resume(r: valkey.Valkey): """ This test verifies that the Connection parser, - be that PythonParser or HiredisParser, + be that PythonParser or LibvalkeyParser, can be interrupted at IO time and then resume parsing. """ conn = Connection(**r.connection_pool.connection_kwargs) @@ -205,8 +205,8 @@ async def test_connection_parse_response_resume(r: valkey.Valkey): @pytest.mark.onlynoncluster @pytest.mark.parametrize( "parser_class", - [_AsyncRESP2Parser, _AsyncRESP3Parser, _AsyncHiredisParser], - ids=["AsyncRESP2Parser", "AsyncRESP3Parser", "AsyncHiredisParser"], + [_AsyncRESP2Parser, _AsyncRESP3Parser, _AsyncLibvalkeyParser], + ids=["AsyncRESP2Parser", "AsyncRESP3Parser", "AsyncLibvalkeyParser"], ) async def test_connection_disconect_race(parser_class, connect_args): """ @@ -220,8 +220,8 @@ async def test_connection_disconect_race(parser_class, connect_args): This test verifies that a read in progress can finish even if the `disconnect()` method is called. """ - if parser_class == _AsyncHiredisParser and not HIREDIS_AVAILABLE: - pytest.skip("Hiredis not available") + if parser_class == _AsyncLibvalkeyParser and not LIBVALKEY_AVAILABLE: + pytest.skip("libvalkey not available") connect_args["parser_class"] = parser_class @@ -234,7 +234,7 @@ async def test_connection_disconect_race(parser_class, connect_args): state = 0 # Mock read function, which wait for a close to happen before returning - # Can either be invoked as two `read()` calls (HiredisParser) + # Can either be invoked as two `read()` calls (LibvalkeyParser) # or as a `readline()` followed by `readexact()` (PythonParser) chunks = [b"$13\r\n", b"Hello, World!\r\n"] @@ -264,7 +264,7 @@ async def do_read(): writer = mock.Mock(spec=asyncio.StreamWriter) writer.transport.get_extra_info.side_effect = None - # for HiredisParser + # for LibvalkeyParser reader.read.side_effect = read # for PythonParser reader.readline.side_effect = read diff --git a/tests/test_asyncio/test_pubsub.py b/tests/test_asyncio/test_pubsub.py index d27e5941..8afb2256 100644 --- a/tests/test_asyncio/test_pubsub.py +++ b/tests/test_asyncio/test_pubsub.py @@ -18,7 +18,7 @@ from tests.conftest import get_protocol_version, skip_if_server_version_lt from valkey.exceptions import ConnectionError from valkey.typing import EncodableT -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .compat import aclosing, create_task, mock @@ -464,7 +464,7 @@ class TestPubSubRESP3Handler: def my_handler(self, message): self.message = ["my handler", message] - @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") + @pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") async def test_push_handler(self, r): if get_protocol_version(r) in [2, "2", None]: return @@ -1051,7 +1051,7 @@ async def get_msg(): # timeout waiting for another message which never arrives assert pubsub.connection.is_connected with patch("valkey._parsers._AsyncRESP2Parser.read_response") as mock1, patch( - "valkey._parsers._AsyncHiredisParser.read_response" + "valkey._parsers._AsyncLibvalkeyParser.read_response" ) as mock2, patch("valkey._parsers._AsyncRESP3Parser.read_response") as mock3: mock1.side_effect = BaseException("boom") mock2.side_effect = BaseException("boom") diff --git a/tests/test_bloom.py b/tests/test_bloom.py index d09f409f..ea4abfeb 100644 --- a/tests/test_bloom.py +++ b/tests/test_bloom.py @@ -3,7 +3,7 @@ import pytest import valkey.commands.bf from valkey.exceptions import ModuleError, ValkeyError -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .conftest import assert_resp_response, is_resp2_connection, skip_ifmodversion_lt @@ -119,7 +119,7 @@ def do_verify(): do_verify() cmds = [] - if HIREDIS_AVAILABLE: + if LIBVALKEY_AVAILABLE: with pytest.raises(ModuleError): cur = client.bf().scandump("myBloom", 0) return diff --git a/tests/test_cache.py b/tests/test_cache.py index e15fad6e..63784101 100644 --- a/tests/test_cache.py +++ b/tests/test_cache.py @@ -9,7 +9,7 @@ from valkey import ValkeyError from valkey._cache import AbstractCache, EvictionPolicy, _LocalCache from valkey.typing import KeyT, ResponseT -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE @pytest.fixture() @@ -34,7 +34,7 @@ def local_cache(): return _LocalCache() -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") class TestLocalCache: @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) @pytest.mark.onlynoncluster @@ -417,7 +417,7 @@ def test_get_from_cache_invalidate_via_get(self, r, r2): assert r.get("foo") == b"barbar" -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlycluster class TestClusterLocalCache: @pytest.mark.parametrize("r", [{"cache": _LocalCache()}], indirect=True) @@ -484,7 +484,7 @@ def test_execute_command_keys_not_provided(self, r): assert cache.get(("GET", "b")) is None -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlynoncluster class TestSentinelLocalCache: @@ -524,7 +524,7 @@ def test_cache_decode_response(self, local_cache, sentinel_setup, master): assert master.get("foo") == "barbar" -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlynoncluster class TestCustomCache: class _CustomCache(AbstractCache): diff --git a/tests/test_command_parser.py b/tests/test_command_parser.py index 80a8b694..7a5dfdb8 100644 --- a/tests/test_command_parser.py +++ b/tests/test_command_parser.py @@ -1,13 +1,13 @@ import pytest from valkey._parsers import CommandsParser -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .conftest import assert_resp_response, skip_if_server_version_lt # The response to COMMAND contains maps inside sets, which are not handled -# by the hiredis-py parser (see https://github.com/redis/hiredis-py/issues/188) -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +# by the parser (see https://github.com/redis/hiredis-py/issues/188) +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") class TestCommandsParser: def test_init_commands(self, r): commands_parser = CommandsParser(r) diff --git a/tests/test_commands.py b/tests/test_commands.py index 67286626..96893306 100644 --- a/tests/test_commands.py +++ b/tests/test_commands.py @@ -18,7 +18,7 @@ parse_info, ) from valkey.client import EMPTY_RESPONSE, NEVER_DECODE -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .conftest import ( _get_client, @@ -4942,8 +4942,8 @@ def test_command_getkeys(self, r): ) # The response to COMMAND contains maps inside sets, which are not handled - # by the hiredis-py parser (see https://github.com/redis/hiredis-py/issues/188) - @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") + # by the parser (see https://github.com/redis/hiredis-py/issues/188) + @pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @skip_if_server_version_lt("2.8.13") def test_command(self, r): res = r.command() diff --git a/tests/test_connection.py b/tests/test_connection.py index 13617e8f..4354cfd2 100644 --- a/tests/test_connection.py +++ b/tests/test_connection.py @@ -6,18 +6,18 @@ import pytest import valkey from valkey import ConnectionPool, Valkey -from valkey._parsers import _HiredisParser, _RESP2Parser, _RESP3Parser, parse_url +from valkey._parsers import _LibvalkeyParser, _RESP2Parser, _RESP3Parser, parse_url from valkey.backoff import NoBackoff from valkey.connection import Connection, SSLConnection, UnixDomainSocketConnection from valkey.exceptions import ConnectionError, InvalidResponse, TimeoutError from valkey.retry import Retry -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .conftest import skip_if_server_version_lt from .mocks import MockSocket -@pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") +@pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @pytest.mark.onlynoncluster def test_invalid_response(r): raw = b"x" @@ -130,17 +130,17 @@ def test_connect_timeout_error_without_retry(self): @pytest.mark.onlynoncluster @pytest.mark.parametrize( "parser_class", - [_RESP2Parser, _RESP3Parser, _HiredisParser], - ids=["RESP2Parser", "RESP3Parser", "HiredisParser"], + [_RESP2Parser, _RESP3Parser, _LibvalkeyParser], + ids=["RESP2Parser", "RESP3Parser", "LibvalkeyParser"], ) def test_connection_parse_response_resume(r: valkey.Valkey, parser_class): """ This test verifies that the Connection parser, - be that PythonParser or HiredisParser, + be that PythonParser or LibvalkeyParser, can be interrupted at IO time and then resume parsing. """ - if parser_class is _HiredisParser and not HIREDIS_AVAILABLE: - pytest.skip("Hiredis not available)") + if parser_class is _LibvalkeyParser and not LIBVALKEY_AVAILABLE: + pytest.skip("Libvalkey not available)") args = dict(r.connection_pool.connection_kwargs) args["parser_class"] = parser_class conn = Connection(**args) diff --git a/tests/test_encoding.py b/tests/test_encoding.py index 3dda182c..c0b891b4 100644 --- a/tests/test_encoding.py +++ b/tests/test_encoding.py @@ -1,7 +1,7 @@ import pytest import valkey from valkey.connection import Connection -from valkey.utils import HIREDIS_PACK_AVAILABLE +from valkey.utils import LIBVALKEY_PACK_AVAILABLE from .conftest import _get_client @@ -76,8 +76,8 @@ def test_replace(self, request): @pytest.mark.skipif( - HIREDIS_PACK_AVAILABLE, - reason="Packing via hiredis does not preserve memoryviews", + LIBVALKEY_PACK_AVAILABLE, + reason="Packing via libvalkey does not preserve memoryviews", ) class TestMemoryviewsAreNotPacked: def test_memoryviews_are_not_packed(self): diff --git a/tests/test_pubsub.py b/tests/test_pubsub.py index 43b38d00..01b5dee8 100644 --- a/tests/test_pubsub.py +++ b/tests/test_pubsub.py @@ -10,7 +10,7 @@ import pytest import valkey from valkey.exceptions import ConnectionError -from valkey.utils import HIREDIS_AVAILABLE +from valkey.utils import LIBVALKEY_AVAILABLE from .conftest import _get_client, is_resp2_connection, skip_if_server_version_lt @@ -588,7 +588,7 @@ class TestPubSubRESP3Handler: def my_handler(self, message): self.message = ["my handler", message] - @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") + @pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") def test_push_handler(self, r): if is_resp2_connection(r): return @@ -600,7 +600,7 @@ def test_push_handler(self, r): assert wait_for_message(p) is None assert self.message == ["my handler", [b"message", b"foo", b"test message"]] - @pytest.mark.skipif(HIREDIS_AVAILABLE, reason="PythonParser only") + @pytest.mark.skipif(LIBVALKEY_AVAILABLE, reason="PythonParser only") @skip_if_server_version_lt("7.0.0") def test_push_handler_sharded_pubsub(self, r): if is_resp2_connection(r): @@ -1136,7 +1136,7 @@ def get_msg(): # timeout waiting for another message which never arrives assert is_connected() with patch("valkey._parsers._RESP2Parser.read_response") as mock1, patch( - "valkey._parsers._HiredisParser.read_response" + "valkey._parsers._LibvalkeyParser.read_response" ) as mock2, patch("valkey._parsers._RESP3Parser.read_response") as mock3: mock1.side_effect = BaseException("boom") mock2.side_effect = BaseException("boom") diff --git a/valkey/_parsers/__init__.py b/valkey/_parsers/__init__.py index b1976013..97f3fd20 100644 --- a/valkey/_parsers/__init__.py +++ b/valkey/_parsers/__init__.py @@ -1,21 +1,21 @@ from .base import BaseParser, _AsyncRESPBase from .commands import AsyncCommandsParser, CommandsParser from .encoders import Encoder -from .hiredis import _AsyncHiredisParser, _HiredisParser +from .libvalkey import _AsyncLibvalkeyParser, _LibvalkeyParser from .resp2 import _AsyncRESP2Parser, _RESP2Parser from .resp3 import _AsyncRESP3Parser, _RESP3Parser from .url_parser import parse_url __all__ = [ "AsyncCommandsParser", - "_AsyncHiredisParser", + "_AsyncLibvalkeyParser", "_AsyncRESPBase", "_AsyncRESP2Parser", "_AsyncRESP3Parser", "CommandsParser", "Encoder", "BaseParser", - "_HiredisParser", + "_LibvalkeyParser", "_RESP2Parser", "_RESP3Parser", "parse_url", diff --git a/valkey/_parsers/hiredis.py b/valkey/_parsers/libvalkey.py similarity index 91% rename from valkey/_parsers/hiredis.py rename to valkey/_parsers/libvalkey.py index 37634ba9..6cfbc137 100644 --- a/valkey/_parsers/hiredis.py +++ b/valkey/_parsers/libvalkey.py @@ -10,7 +10,7 @@ from ..exceptions import ConnectionError, InvalidResponse, ValkeyError from ..typing import EncodableT -from ..utils import HIREDIS_AVAILABLE +from ..utils import LIBVALKEY_AVAILABLE from .base import AsyncBaseParser, BaseParser from .socket import ( NONBLOCKING_EXCEPTION_ERROR_NUMBERS, @@ -19,25 +19,25 @@ SERVER_CLOSED_CONNECTION_ERROR, ) -# Used to signal that hiredis-py does not have enough data to parse. +# Used to signal that libvalkey-py does not have enough data to parse. # Using `False` or `None` is not reliable, given that the parser can # return `False` or `None` for legitimate reasons from RESP payloads. NOT_ENOUGH_DATA = object() -class _HiredisReaderArgs(TypedDict, total=False): +class _LibvalkeyReaderArgs(TypedDict, total=False): protocolError: Callable[[str], Exception] replyError: Callable[[str], Exception] encoding: Optional[str] errors: Optional[str] -class _HiredisParser(BaseParser): - "Parser class for connections using Hiredis" +class _LibvalkeyParser(BaseParser): + "Parser class for connections using libvalkey" def __init__(self, socket_read_size): - if not HIREDIS_AVAILABLE: - raise ValkeyError("Hiredis is not installed") + if not LIBVALKEY_AVAILABLE: + raise ValkeyError("libvalkey is not installed") self.socket_read_size = socket_read_size self._buffer = bytearray(socket_read_size) @@ -48,7 +48,7 @@ def __del__(self): pass def on_connect(self, connection, **kwargs): - import hiredis + import libvalkey self._sock = connection._sock self._socket_timeout = connection.socket_timeout @@ -61,7 +61,7 @@ def on_connect(self, connection, **kwargs): if connection.encoder.decode_responses: kwargs["encoding"] = connection.encoder.encoding - self._reader = hiredis.Reader(**kwargs) + self._reader = libvalkey.Reader(**kwargs) self._next_response = NOT_ENOUGH_DATA def on_disconnect(self): @@ -144,22 +144,22 @@ def read_response(self, disable_decoding=False): return response -class _AsyncHiredisParser(AsyncBaseParser): - """Async implementation of parser class for connections using Hiredis""" +class _AsyncLibvalkeyParser(AsyncBaseParser): + """Async implementation of parser class for connections using libvalkey""" __slots__ = ("_reader",) def __init__(self, socket_read_size: int): - if not HIREDIS_AVAILABLE: - raise ValkeyError("Hiredis is not available.") + if not LIBVALKEY_AVAILABLE: + raise ValkeyError("libvalkey is not available.") super().__init__(socket_read_size=socket_read_size) self._reader = None def on_connect(self, connection): - import hiredis + import libvalkey self._stream = connection._reader - kwargs: _HiredisReaderArgs = { + kwargs: _LibvalkeyReaderArgs = { "protocolError": InvalidResponse, "replyError": self.parse_error, "notEnoughData": NOT_ENOUGH_DATA, @@ -168,7 +168,7 @@ def on_connect(self, connection): kwargs["encoding"] = connection.encoder.encoding kwargs["errors"] = connection.encoder.encoding_errors - self._reader = hiredis.Reader(**kwargs) + self._reader = libvalkey.Reader(**kwargs) self._connected = True def on_disconnect(self): diff --git a/valkey/asyncio/client.py b/valkey/asyncio/client.py index 960de835..2098d585 100644 --- a/valkey/asyncio/client.py +++ b/valkey/asyncio/client.py @@ -70,7 +70,7 @@ ) from valkey.typing import ChannelT, EncodableT, KeyT from valkey.utils import ( - HIREDIS_AVAILABLE, + LIBVALKEY_AVAILABLE, _set_info_logger, deprecated_function, get_lib_version, @@ -913,7 +913,7 @@ async def connect(self): self.connection.register_connect_callback(self.on_connect) else: await self.connection.connect() - if self.push_handler_func is not None and not HIREDIS_AVAILABLE: + if self.push_handler_func is not None and not LIBVALKEY_AVAILABLE: self.connection._parser.set_pubsub_push_handler(self.push_handler_func) async def _disconnect_raise_connect(self, conn, error): diff --git a/valkey/asyncio/connection.py b/valkey/asyncio/connection.py index 573d41b3..3f3e2059 100644 --- a/valkey/asyncio/connection.py +++ b/valkey/asyncio/connection.py @@ -45,7 +45,7 @@ ValkeyError, ) from valkey.typing import EncodableT, KeysT, ResponseT -from valkey.utils import HIREDIS_AVAILABLE, get_lib_version, str_if_bytes +from valkey.utils import LIBVALKEY_AVAILABLE, get_lib_version, str_if_bytes from .._cache import ( DEFAULT_ALLOW_LIST, @@ -57,7 +57,7 @@ from .._parsers import ( BaseParser, Encoder, - _AsyncHiredisParser, + _AsyncLibvalkeyParser, _AsyncRESP2Parser, _AsyncRESP3Parser, ) @@ -76,9 +76,9 @@ class _Sentinel(enum.Enum): SENTINEL = _Sentinel.sentinel -DefaultParser: Type[Union[_AsyncRESP2Parser, _AsyncRESP3Parser, _AsyncHiredisParser]] -if HIREDIS_AVAILABLE: - DefaultParser = _AsyncHiredisParser +DefaultParser: Type[Union[_AsyncRESP2Parser, _AsyncRESP3Parser, _AsyncLibvalkeyParser]] +if LIBVALKEY_AVAILABLE: + DefaultParser = _AsyncLibvalkeyParser else: DefaultParser = _AsyncRESP2Parser @@ -557,7 +557,7 @@ async def read_response( if ( read_timeout is not None and self.protocol in ["3", 3] - and not HIREDIS_AVAILABLE + and not LIBVALKEY_AVAILABLE ): async with async_timeout(read_timeout): response = await self._parser.read_response( @@ -568,7 +568,7 @@ async def read_response( response = await self._parser.read_response( disable_decoding=disable_decoding ) - elif self.protocol in ["3", 3] and not HIREDIS_AVAILABLE: + elif self.protocol in ["3", 3] and not LIBVALKEY_AVAILABLE: response = await self._parser.read_response( disable_decoding=disable_decoding, push_request=push_request ) diff --git a/valkey/client.py b/valkey/client.py index eed48b45..a0a5b1ee 100755 --- a/valkey/client.py +++ b/valkey/client.py @@ -44,7 +44,7 @@ from valkey.lock import Lock from valkey.retry import Retry from valkey.utils import ( - HIREDIS_AVAILABLE, + LIBVALKEY_AVAILABLE, _set_info_logger, get_lib_version, safe_str, @@ -807,7 +807,7 @@ def execute_command(self, *args): # register a callback that re-subscribes to any channels we # were listening to when we were disconnected self.connection.register_connect_callback(self.on_connect) - if self.push_handler_func is not None and not HIREDIS_AVAILABLE: + if self.push_handler_func is not None and not LIBVALKEY_AVAILABLE: self.connection._parser.set_pubsub_push_handler(self.push_handler_func) connection = self.connection kwargs = {"check_health": not self.subscribed} diff --git a/valkey/cluster.py b/valkey/cluster.py index b9c125a8..0496ccbd 100644 --- a/valkey/cluster.py +++ b/valkey/cluster.py @@ -34,7 +34,7 @@ from valkey.lock import Lock from valkey.retry import Retry from valkey.utils import ( - HIREDIS_AVAILABLE, + LIBVALKEY_AVAILABLE, dict_merge, list_keys_to_dict, merge_result, @@ -1823,7 +1823,7 @@ def execute_command(self, *args): # register a callback that re-subscribes to any channels we # were listening to when we were disconnected self.connection.register_connect_callback(self.on_connect) - if self.push_handler_func is not None and not HIREDIS_AVAILABLE: + if self.push_handler_func is not None and not LIBVALKEY_AVAILABLE: self.connection._parser.set_pubsub_push_handler(self.push_handler_func) connection = self.connection self._execute(connection, connection.send_command, *args) diff --git a/valkey/commands/bf/commands.py b/valkey/commands/bf/commands.py index 0e70cd3a..cc739e68 100644 --- a/valkey/commands/bf/commands.py +++ b/valkey/commands/bf/commands.py @@ -1,6 +1,6 @@ from valkey.client import NEVER_DECODE from valkey.exceptions import ModuleError -from valkey.utils import HIREDIS_AVAILABLE, deprecated_function +from valkey.utils import LIBVALKEY_AVAILABLE, deprecated_function BF_RESERVE = "BF.RESERVE" BF_ADD = "BF.ADD" @@ -139,8 +139,10 @@ def scandump(self, key, iter): This command will return successive (iter, data) pairs until (0, NULL) to indicate completion. For more information see `BF.SCANDUMP `_. """ # noqa - if HIREDIS_AVAILABLE: - raise ModuleError("This command cannot be used when hiredis is available.") + if LIBVALKEY_AVAILABLE: + raise ModuleError( + "This command cannot be used when libvalkey is available." + ) params = [key, iter] options = {} diff --git a/valkey/connection.py b/valkey/connection.py index d34588d5..35641dad 100644 --- a/valkey/connection.py +++ b/valkey/connection.py @@ -18,7 +18,7 @@ AbstractCache, _LocalCache, ) -from ._parsers import Encoder, _HiredisParser, _RESP2Parser, _RESP3Parser +from ._parsers import Encoder, _LibvalkeyParser, _RESP2Parser, _RESP3Parser from .backoff import NoBackoff from .credentials import CredentialProvider, UsernamePasswordCredentialProvider from .exceptions import ( @@ -35,15 +35,15 @@ from .typing import KeysT, ResponseT from .utils import ( CRYPTOGRAPHY_AVAILABLE, - HIREDIS_AVAILABLE, - HIREDIS_PACK_AVAILABLE, + LIBVALKEY_AVAILABLE, + LIBVALKEY_PACK_AVAILABLE, SSL_AVAILABLE, get_lib_version, str_if_bytes, ) -if HIREDIS_AVAILABLE: - import hiredis +if LIBVALKEY_AVAILABLE: + import libvalkey SYM_STAR = b"*" SYM_DOLLAR = b"$" @@ -54,14 +54,14 @@ SENTINEL = object() -DefaultParser: Type[Union[_RESP2Parser, _RESP3Parser, _HiredisParser]] -if HIREDIS_AVAILABLE: - DefaultParser = _HiredisParser +DefaultParser: Type[Union[_RESP2Parser, _RESP3Parser, _LibvalkeyParser]] +if LIBVALKEY_AVAILABLE: + DefaultParser = _LibvalkeyParser else: DefaultParser = _RESP2Parser -class HiredisRespSerializer: +class LibvalkeyRespSerializer: def pack(self, *args: List): """Pack a series of arguments into the Valkey protocol""" output = [] @@ -71,7 +71,7 @@ def pack(self, *args: List): elif b" " in args[0]: args = tuple(args[0].split()) + args[1:] try: - output.append(hiredis.pack_command(args)) + output.append(libvalkey.pack_command(args)) except TypeError: _, value, traceback = sys.exc_info() raise DataError(value).with_traceback(traceback) @@ -258,8 +258,8 @@ def __del__(self): def _construct_command_packer(self, packer): if packer is not None: return packer - elif HIREDIS_PACK_AVAILABLE: - return HiredisRespSerializer() + elif LIBVALKEY_PACK_AVAILABLE: + return LibvalkeyRespSerializer() else: return PythonRespSerializer(self._buffer_cutoff, self.encoder.encode) @@ -539,7 +539,7 @@ def read_response( host_error = self._host_error() try: - if self.protocol in ["3", 3] and not HIREDIS_AVAILABLE: + if self.protocol in ["3", 3] and not LIBVALKEY_AVAILABLE: response = self._parser.read_response( disable_decoding=disable_decoding, push_request=push_request ) diff --git a/valkey/utils.py b/valkey/utils.py index 4826cd2c..5c325165 100644 --- a/valkey/utils.py +++ b/valkey/utils.py @@ -4,14 +4,14 @@ from typing import Any, Dict, Mapping, Union try: - import hiredis # noqa + import libvalkey # noqa - # Only support Hiredis >= 1.0: - HIREDIS_AVAILABLE = not hiredis.__version__.startswith("0.") - HIREDIS_PACK_AVAILABLE = hasattr(hiredis, "pack_command") + # Only support libvalkey >= 1.0: + LIBVALKEY_AVAILABLE = not libvalkey.__version__.startswith("0.") + LIBVALKEY_PACK_AVAILABLE = hasattr(libvalkey, "pack_command") except ImportError: - HIREDIS_AVAILABLE = False - HIREDIS_PACK_AVAILABLE = False + LIBVALKEY_AVAILABLE = False + LIBVALKEY_PACK_AVAILABLE = False try: import ssl # noqa