Skip to content

Commit

Permalink
Replace hiredis dependency with valkey
Browse files Browse the repository at this point in the history
Signed-off-by: Mikhail Koviazin <[email protected]>
  • Loading branch information
mkmkme committed Aug 1, 2024
1 parent 2b1ce71 commit 1768319
Show file tree
Hide file tree
Showing 26 changed files with 117 additions and 115 deletions.
2 changes: 1 addition & 1 deletion .github/wordlist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ firsttimersonly
fo
genindex
gmail
hiredis
html
http
https
Expand All @@ -101,6 +100,7 @@ json
keyslot
keyspace
kwarg
libvalkey
linters
localhost
lua
Expand Down
14 changes: 7 additions & 7 deletions .github/workflows/integration.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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}}]
Expand All @@ -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
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions benchmarks/socket_read_size.py
Original file line number Diff line number Diff line change
@@ -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],
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -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"],
},
)
2 changes: 1 addition & 1 deletion tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
4 changes: 2 additions & 2 deletions tests/test_asyncio/test_bloom.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
8 changes: 4 additions & 4 deletions tests/test_asyncio/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:

Expand Down
18 changes: 9 additions & 9 deletions tests/test_asyncio/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
import valkey
from tests.conftest import skip_if_server_version_lt
from valkey._parsers import (
_AsyncHiredisParser,
_AsyncLibvalkeyParser,
_AsyncRESP2Parser,
_AsyncRESP3Parser,
_AsyncRESPBase,
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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):
"""
Expand All @@ -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

Expand All @@ -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"]

Expand Down Expand Up @@ -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
Expand Down
6 changes: 3 additions & 3 deletions tests/test_asyncio/test_pubsub.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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")
Expand Down
4 changes: 2 additions & 2 deletions tests/test_bloom.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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
Expand Down
10 changes: 5 additions & 5 deletions tests/test_cache.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand All @@ -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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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:

Expand Down Expand Up @@ -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):
Expand Down
6 changes: 3 additions & 3 deletions tests/test_command_parser.py
Original file line number Diff line number Diff line change
@@ -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)
Expand Down
6 changes: 3 additions & 3 deletions tests/test_commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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()
Expand Down
Loading

0 comments on commit 1768319

Please sign in to comment.