diff --git a/docs/conf.py b/docs/conf.py
index bcfa4aadd7..cdfa343929 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -63,6 +63,7 @@
"trio": ("https://trio.readthedocs.io/en/stable/", None),
"pydantic": ("https://docs.pydantic.dev/latest/", None),
"typing_extensions": ("https://typing-extensions.readthedocs.io/en/stable/", None),
+ "valkey": ("https://valkey-py.readthedocs.io/en/latest/", None),
}
napoleon_google_docstring = True
@@ -102,6 +103,7 @@
(PY_CLASS, "sqlalchemy.dialects.postgresql.named_types.ENUM"),
(PY_CLASS, "sqlalchemy.orm.decl_api.DeclarativeMeta"),
(PY_CLASS, "sqlalchemy.sql.sqltypes.TupleType"),
+ (PY_CLASS, "valkey.asyncio.Valkey"),
(PY_METH, "_types.TypeDecorator.process_bind_param"),
(PY_METH, "_types.TypeDecorator.process_result_value"),
(PY_METH, "litestar.typing.ParsedType.is_subclass_of"),
diff --git a/docs/reference/stores/index.rst b/docs/reference/stores/index.rst
index 8123ba1da4..23095869c3 100644
--- a/docs/reference/stores/index.rst
+++ b/docs/reference/stores/index.rst
@@ -8,3 +8,4 @@ stores
memory
redis
registry
+ valkey
diff --git a/docs/reference/stores/valkey.rst b/docs/reference/stores/valkey.rst
new file mode 100644
index 0000000000..288118c2e3
--- /dev/null
+++ b/docs/reference/stores/valkey.rst
@@ -0,0 +1,5 @@
+valkey
+======
+
+.. automodule:: litestar.stores.valkey
+ :members:
diff --git a/docs/usage/stores.rst b/docs/usage/stores.rst
index e683eb81e3..253cc9deee 100644
--- a/docs/usage/stores.rst
+++ b/docs/usage/stores.rst
@@ -35,6 +35,12 @@ Built-in stores
A store backend by `redis `_. It offers all the guarantees and features of Redis, making it
suitable for almost all applications. Offers `namespacing`_.
+:class:`ValKeyStore `
+ A store backed by `valkey `_, a fork of Redis created as the result of Redis' license changes.
+ Similarly to the RedisStore, it is suitable for almost all applications and supports `namespacing`_.
+ At the time of writing, :class:`Valkey ` is equivalent to :class:`redis.asyncio.Redis`,
+ and all notes pertaining to Redis also apply to Valkey.
+
.. admonition:: Why not memcached?
:class: info
diff --git a/litestar/stores/valkey.py b/litestar/stores/valkey.py
new file mode 100644
index 0000000000..667e305e11
--- /dev/null
+++ b/litestar/stores/valkey.py
@@ -0,0 +1,210 @@
+from __future__ import annotations
+
+from datetime import timedelta
+from typing import TYPE_CHECKING, cast
+
+from valkey.asyncio import Valkey
+from valkey.asyncio.connection import ConnectionPool
+
+from litestar.exceptions import ImproperlyConfiguredException
+from litestar.types import Empty, EmptyType
+from litestar.utils.empty import value_or_default
+
+from .base import NamespacedStore
+
+if TYPE_CHECKING:
+ from types import TracebackType
+
+
+__all__ = ("ValkeyStore",)
+
+
+class ValkeyStore(NamespacedStore):
+ """Valkey based, thread and process safe asynchronous key/value store."""
+
+ __slots__ = (
+ "_delete_all_script",
+ "_get_and_renew_script",
+ "_valkey",
+ "handle_client_shutdown",
+ )
+
+ def __init__(
+ self, valkey: Valkey, namespace: str | None | EmptyType = Empty, handle_client_shutdown: bool = False
+ ) -> None:
+ """Initialize :class:`ValkeyStore`
+
+ Args:
+ valkey: An :class:`valkey.asyncio.Valkey` instance
+ namespace: A key prefix to simulate a namespace in valkey. If not given,
+ defaults to ``LITESTAR``. Namespacing can be explicitly disabled by passing
+ ``None``. This will make :meth:`.delete_all` unavailable.
+ handle_client_shutdown: If ``True``, handle the shutdown of the `valkey` instance automatically during the store's lifespan. Should be set to `True` unless the shutdown is handled externally
+ """
+ self._valkey = valkey
+ self.namespace: str | None = value_or_default(namespace, "LITESTAR")
+ self.handle_client_shutdown = handle_client_shutdown
+
+ # script to get and renew a key in one atomic step
+ self._get_and_renew_script = self._valkey.register_script(
+ b"""
+ local key = KEYS[1]
+ local renew = tonumber(ARGV[1])
+
+ local data = server.call('GET', key)
+ local ttl = server.call('TTL', key)
+
+ if ttl > 0 then
+ server.call('EXPIRE', key, renew)
+ end
+
+ return data
+ """
+ )
+
+ # script to delete all keys in the namespace
+ self._delete_all_script = self._valkey.register_script(
+ b"""
+ local cursor = 0
+
+ repeat
+ local result = server.call('SCAN', cursor, 'MATCH', ARGV[1])
+ for _,key in ipairs(result[2]) do
+ server.call('UNLINK', key)
+ end
+ cursor = tonumber(result[1])
+ until cursor == 0
+ """
+ )
+
+ async def _shutdown(self) -> None:
+ if self.handle_client_shutdown:
+ await self._valkey.aclose(close_connection_pool=True)
+
+ async def __aexit__(
+ self,
+ exc_type: type[BaseException] | None,
+ exc_val: BaseException | None,
+ exc_tb: TracebackType | None,
+ ) -> None:
+ await self._shutdown()
+
+ @classmethod
+ def with_client(
+ cls,
+ url: str = "valkey://localhost:6379",
+ *,
+ db: int | None = None,
+ port: int | None = None,
+ username: str | None = None,
+ password: str | None = None,
+ namespace: str | None | EmptyType = Empty,
+ ) -> ValkeyStore:
+ """Initialize a :class:`ValkeyStore` instance with a new class:`valkey.asyncio.Valkey` instance.
+
+ Args:
+ url: Valkey URL to connect to
+ db: Valkey database to use
+ port: Valkey port to use
+ username: Valkey username to use
+ password: Valkey password to use
+ namespace: Virtual key namespace to use
+ """
+ pool: ConnectionPool = ConnectionPool.from_url(
+ url=url,
+ db=db,
+ decode_responses=False,
+ port=port,
+ username=username,
+ password=password,
+ )
+ return cls(
+ valkey=Valkey(connection_pool=pool),
+ namespace=namespace,
+ handle_client_shutdown=True,
+ )
+
+ def with_namespace(self, namespace: str) -> ValkeyStore:
+ """Return a new :class:`ValkeyStore` with a nested virtual key namespace.
+ The current instances namespace will serve as a prefix for the namespace, so it
+ can be considered the parent namespace.
+ """
+ return type(self)(
+ valkey=self._valkey,
+ namespace=f"{self.namespace}_{namespace}" if self.namespace else namespace,
+ handle_client_shutdown=self.handle_client_shutdown,
+ )
+
+ def _make_key(self, key: str) -> str:
+ prefix = f"{self.namespace}:" if self.namespace else ""
+ return prefix + key
+
+ async def set(self, key: str, value: str | bytes, expires_in: int | timedelta | None = None) -> None:
+ """Set a value.
+
+ Args:
+ key: Key to associate the value with
+ value: Value to store
+ expires_in: Time in seconds before the key is considered expired
+
+ Returns:
+ ``None``
+ """
+ if isinstance(value, str):
+ value = value.encode("utf-8")
+ await self._valkey.set(self._make_key(key), value, ex=expires_in)
+
+ async def get(self, key: str, renew_for: int | timedelta | None = None) -> bytes | None:
+ """Get a value.
+
+ Args:
+ key: Key associated with the value
+ renew_for: If given and the value had an initial expiry time set, renew the
+ expiry time for ``renew_for`` seconds. If the value has not been set
+ with an expiry time this is a no-op. Atomicity of this step is guaranteed
+ by using a lua script to execute fetch and renewal. If ``renew_for`` is
+ not given, the script will be bypassed so no overhead will occur
+
+ Returns:
+ The value associated with ``key`` if it exists and is not expired, else
+ ``None``
+ """
+ key = self._make_key(key)
+ if renew_for:
+ if isinstance(renew_for, timedelta):
+ renew_for = renew_for.seconds
+ data = await self._get_and_renew_script(keys=[key], args=[renew_for])
+ return cast("bytes | None", data)
+ return await self._valkey.get(key) # type: ignore[no-any-return]
+
+ async def delete(self, key: str) -> None:
+ """Delete a value.
+
+ If no such key exists, this is a no-op.
+
+ Args:
+ key: Key of the value to delete
+ """
+ await self._valkey.delete(self._make_key(key))
+
+ async def delete_all(self) -> None:
+ """Delete all stored values in the virtual key namespace.
+
+ Raises:
+ ImproperlyConfiguredException: If no namespace was configured
+ """
+ if not self.namespace:
+ raise ImproperlyConfiguredException("Cannot perform delete operation: No namespace configured")
+
+ await self._delete_all_script(keys=[], args=[f"{self.namespace}*:*"])
+
+ async def exists(self, key: str) -> bool:
+ """Check if a given ``key`` exists."""
+ return await self._valkey.exists(self._make_key(key)) == 1 # type: ignore[no-any-return]
+
+ async def expires_in(self, key: str) -> int | None:
+ """Get the time in seconds ``key`` expires in. If no such ``key`` exists or no
+ expiry time was set, return ``None``.
+ """
+ ttl = await self._valkey.ttl(self._make_key(key))
+ return None if ttl == -2 else ttl
diff --git a/pyproject.toml b/pyproject.toml
index 98709540fa..2a18071ef6 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -83,7 +83,7 @@ brotli = ["brotli"]
cli = ["jsbeautifier", "uvicorn[standard]", "uvloop>=0.18.0; sys_platform != 'win32'"]
cryptography = ["cryptography"]
full = [
- "litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog]",
+ "litestar[annotated-types,attrs,brotli,cli,cryptography,jinja,jwt,mako,minijinja,opentelemetry,piccolo,picologging,prometheus,pydantic,redis,sqlalchemy,standard,structlog,valkey]",
]
jinja = ["jinja2>=3.1.2"]
jwt = [
@@ -98,6 +98,7 @@ picologging = ["picologging"]
prometheus = ["prometheus-client"]
pydantic = ["pydantic", "email-validator", "pydantic-extra-types"]
redis = ["redis[hiredis]>=4.4.4"]
+valkey = ["valkey[libvalkey]>=6.0.2"]
sqlalchemy = ["advanced-alchemy>=0.2.2"]
standard = ["jinja2", "jsbeautifier", "uvicorn[standard]", "uvloop>=0.18.0; sys_platform != 'win32'", "fast-query-parsers>=1.0.2"]
structlog = ["structlog"]
diff --git a/tests/conftest.py b/tests/conftest.py
index e4ae950d22..de243a37e2 100644
--- a/tests/conftest.py
+++ b/tests/conftest.py
@@ -18,6 +18,8 @@
from redis.asyncio import Redis as AsyncRedis
from redis.client import Redis
from time_machine import travel
+from valkey.asyncio import Valkey as AsyncValkey
+from valkey.client import Valkey
from litestar.logging import LoggingConfig
from litestar.middleware.session import SessionMiddleware
@@ -29,6 +31,7 @@
from litestar.stores.file import FileStore
from litestar.stores.memory import MemoryStore
from litestar.stores.redis import RedisStore
+from litestar.stores.valkey import ValkeyStore
from litestar.testing import RequestFactory
from tests.helpers import not_none
@@ -82,6 +85,11 @@ def redis_store(redis_client: AsyncRedis) -> RedisStore:
return RedisStore(redis=redis_client)
+@pytest.fixture()
+def valkey_store(valkey_client: AsyncValkey) -> ValkeyStore:
+ return ValkeyStore(valkey=valkey_client)
+
+
@pytest.fixture()
def memory_store() -> MemoryStore:
return MemoryStore()
@@ -105,7 +113,12 @@ def file_store_create_directories_flag_false(tmp_path: Path) -> FileStore:
@pytest.fixture(
- params=[pytest.param("redis_store", marks=pytest.mark.xdist_group("redis")), "memory_store", "file_store"]
+ params=[
+ pytest.param("redis_store", marks=pytest.mark.xdist_group("redis")),
+ pytest.param("valkey_store", marks=pytest.mark.xdist_group("valkey")),
+ "memory_store",
+ "file_store",
+ ]
)
def store(request: FixtureRequest) -> Store:
return cast("Store", request.getfixturevalue(request.param))
@@ -327,6 +340,20 @@ async def redis_client(docker_ip: str, redis_service: None) -> AsyncGenerator[As
pass
+@pytest.fixture()
+async def valkey_client(docker_ip: str, valkey_service: None) -> AsyncGenerator[AsyncValkey, None]:
+ # this is to get around some weirdness with pytest-asyncio and valkey interaction
+ # on 3.8 and 3.9
+
+ Valkey(host=docker_ip, port=6381).flushall()
+ client: AsyncValkey = AsyncValkey(host=docker_ip, port=6381)
+ yield client
+ try:
+ await client.aclose()
+ except RuntimeError:
+ pass
+
+
@pytest.fixture(autouse=True)
def _patch_openapi_config(monkeypatch: pytest.MonkeyPatch) -> None:
monkeypatch.setattr("litestar.app.DEFAULT_OPENAPI_CONFIG", OpenAPIConfig(title="Litestar API", version="1.0.0"))
diff --git a/tests/docker-compose.yml b/tests/docker-compose.yml
index b3d25160ee..2c3b69a283 100644
--- a/tests/docker-compose.yml
+++ b/tests/docker-compose.yml
@@ -12,3 +12,8 @@ services:
restart: always
ports:
- "6397:6379" # use a non-standard port here
+ valkey:
+ image: valkey/valkey:latest
+ restart: always
+ ports:
+ - "6381:6379" # also a non-standard port
diff --git a/tests/docker_service_fixtures.py b/tests/docker_service_fixtures.py
index 6efca36979..84e78d48e6 100644
--- a/tests/docker_service_fixtures.py
+++ b/tests/docker_service_fixtures.py
@@ -13,6 +13,8 @@
import pytest
from redis.asyncio import Redis as AsyncRedis
from redis.exceptions import ConnectionError as RedisConnectionError
+from valkey.asyncio import Valkey as AsyncValkey
+from valkey.exceptions import ConnectionError as ValkeyConnectionError
from litestar.utils import ensure_async_callable
@@ -127,6 +129,21 @@ async def redis_service(docker_services: DockerServiceRegistry) -> None:
await docker_services.start("redis", check=redis_responsive)
+async def valkey_responsive(host: str) -> bool:
+ client: AsyncValkey = AsyncValkey(host=host, port=6381)
+ try:
+ return await client.ping()
+ except (ConnectionError, ValkeyConnectionError):
+ return False
+ finally:
+ await client.aclose()
+
+
+@pytest.fixture()
+async def valkey_service(docker_services: DockerServiceRegistry) -> None:
+ await docker_services.start("valkey", check=valkey_responsive)
+
+
async def postgres_responsive(host: str) -> bool:
try:
conn = await asyncpg.connect(
diff --git a/tests/unit/test_stores.py b/tests/unit/test_stores.py
index f28b71017c..a37b836d52 100644
--- a/tests/unit/test_stores.py
+++ b/tests/unit/test_stores.py
@@ -19,9 +19,11 @@
from litestar.stores.memory import MemoryStore
from litestar.stores.redis import RedisStore
from litestar.stores.registry import StoreRegistry
+from litestar.stores.valkey import ValkeyStore
if TYPE_CHECKING:
from redis.asyncio import Redis
+ from valkey.asyncio import Valkey
from litestar.stores.base import NamespacedStore, Store
@@ -31,6 +33,11 @@ def mock_redis() -> None:
patch("litestar.Store.redis_backend.Redis")
+@pytest.fixture()
+def mock_valkey() -> None:
+ patch("litestar.Store.valkey_backend.Valkey")
+
+
async def test_get(store: Store) -> None:
key = "key"
value = b"value"
@@ -70,6 +77,8 @@ async def test_expires(store: Store, frozen_datetime: Coordinates) -> None:
# shifting time does not affect the Redis instance
# this is done to emulate auto-expiration
await store._redis.expire(f"{store.namespace}:foo", 0)
+ if isinstance(store, ValkeyStore):
+ await store._valkey.expire(f"{store.namespace}:foo", 0)
stored_value = await store.get("foo")
@@ -79,7 +88,7 @@ async def test_expires(store: Store, frozen_datetime: Coordinates) -> None:
@pytest.mark.flaky(reruns=5)
@pytest.mark.parametrize("renew_for", [10, timedelta(seconds=10)])
async def test_get_and_renew(store: Store, renew_for: int | timedelta, frozen_datetime: Coordinates) -> None:
- if isinstance(store, RedisStore):
+ if isinstance(store, (RedisStore, ValkeyStore)):
pytest.skip()
await store.set("foo", b"bar", expires_in=1)
@@ -108,6 +117,22 @@ async def test_get_and_renew_redis(redis_store: RedisStore, renew_for: int | tim
assert stored_value is not None
+@pytest.mark.flaky(reruns=5)
+@pytest.mark.parametrize("renew_for", [10, timedelta(seconds=10)])
+@pytest.mark.xdist_group("valkey")
+async def test_get_and_renew_valkey(valkey_store: ValkeyStore, renew_for: int | timedelta) -> None:
+ # we can't sleep() in frozen datetime, and frozen datetime doesn't affect the redis
+ # instance, so we test this separately
+ await valkey_store.set("foo", b"bar", expires_in=1)
+ await valkey_store.get("foo", renew_for=renew_for)
+
+ await asyncio.sleep(1.1)
+
+ stored_value = await valkey_store.get("foo")
+
+ assert stored_value is not None
+
+
async def test_delete(store: Store) -> None:
key = "key"
await store.set(key, b"value", 60)
@@ -152,7 +177,7 @@ async def test_delete_all(store: Store) -> None:
async def test_expires_in(store: Store, frozen_datetime: Coordinates) -> None:
- if not isinstance(store, RedisStore):
+ if not isinstance(store, (RedisStore, ValkeyStore)):
pytest.xfail("bug in FileStore and MemoryStore")
assert await store.expires_in("foo") is None
@@ -165,7 +190,10 @@ async def test_expires_in(store: Store, frozen_datetime: Coordinates) -> None:
assert expiration is not None
assert math.ceil(expiration / 10) == 1
- await store._redis.expire(f"{store.namespace}:foo", 0)
+ if isinstance(store, RedisStore):
+ await store._redis.expire(f"{store.namespace}:foo", 0)
+ elif isinstance(store, ValkeyStore):
+ await store._valkey.expire(f"{store.namespace}:foo", 0)
expiration = await store.expires_in("foo")
assert expiration is None
@@ -181,6 +209,17 @@ def test_redis_with_client_default(connection_pool_from_url_mock: Mock, mock_red
assert backend._redis is mock_redis.return_value
+@patch("litestar.stores.valkey.Valkey")
+@patch("litestar.stores.valkey.ConnectionPool.from_url")
+def test_valkey_with_client_default(connection_pool_from_url_mock: Mock, mock_valkey: Mock) -> None:
+ backend = ValkeyStore.with_client()
+ connection_pool_from_url_mock.assert_called_once_with(
+ url="valkey://localhost:6379", db=None, port=None, username=None, password=None, decode_responses=False
+ )
+ mock_valkey.assert_called_once_with(connection_pool=connection_pool_from_url_mock.return_value)
+ assert backend._valkey is mock_valkey.return_value
+
+
@patch("litestar.stores.redis.Redis")
@patch("litestar.stores.redis.ConnectionPool.from_url")
def test_redis_with_non_default(connection_pool_from_url_mock: Mock, mock_redis: Mock) -> None:
@@ -197,6 +236,22 @@ def test_redis_with_non_default(connection_pool_from_url_mock: Mock, mock_redis:
assert backend._redis is mock_redis.return_value
+@patch("litestar.stores.valkey.Valkey")
+@patch("litestar.stores.valkey.ConnectionPool.from_url")
+def test_valkey_with_non_default(connection_pool_from_url_mock: Mock, mock_valkey: Mock) -> None:
+ url = "valkey://localhost"
+ db = 2
+ port = 1234
+ username = "user"
+ password = "password"
+ backend = ValkeyStore.with_client(url=url, db=db, port=port, username=username, password=password)
+ connection_pool_from_url_mock.assert_called_once_with(
+ url=url, db=db, port=port, username=username, password=password, decode_responses=False
+ )
+ mock_valkey.assert_called_once_with(connection_pool=connection_pool_from_url_mock.return_value)
+ assert backend._valkey is mock_valkey.return_value
+
+
@pytest.mark.xdist_group("redis")
async def test_redis_delete_all(redis_store: RedisStore) -> None:
await redis_store._redis.set("test_key", b"test_value")
@@ -216,6 +271,25 @@ async def test_redis_delete_all(redis_store: RedisStore) -> None:
assert stored_value == b"test_value" # check it doesn't delete other values
+@pytest.mark.xdist_group("valkey")
+async def test_valkey_delete_all(valkey_store: ValkeyStore) -> None:
+ await valkey_store._valkey.set("test_key", b"test_value")
+
+ keys = []
+ for i in range(10):
+ key = f"key-{i}"
+ keys.append(key)
+ await valkey_store.set(key, b"value", expires_in=10 if i % 2 else None)
+
+ await valkey_store.delete_all()
+
+ for key in keys:
+ assert await valkey_store.get(key) is None
+
+ stored_value = await valkey_store._valkey.get("test_key")
+ assert stored_value == b"test_value" # check it doesn't delete other values
+
+
@pytest.mark.xdist_group("redis")
async def test_redis_delete_all_no_namespace_raises(redis_client: Redis) -> None:
redis_store = RedisStore(redis=redis_client, namespace=None)
@@ -224,12 +298,26 @@ async def test_redis_delete_all_no_namespace_raises(redis_client: Redis) -> None
await redis_store.delete_all()
+@pytest.mark.xdist_group("valkey")
+async def test_valkey_delete_all_no_namespace_raises(valkey_client: Valkey) -> None:
+ valkey_store = ValkeyStore(valkey=valkey_client, namespace=None)
+
+ with pytest.raises(ImproperlyConfiguredException):
+ await valkey_store.delete_all()
+
+
@pytest.mark.xdist_group("redis")
def test_redis_namespaced_key(redis_store: RedisStore) -> None:
assert redis_store.namespace == "LITESTAR"
assert redis_store._make_key("foo") == "LITESTAR:foo"
+@pytest.mark.xdist_group("valkey")
+def test_valkey_namespaced_key(valkey_store: ValkeyStore) -> None:
+ assert valkey_store.namespace == "LITESTAR"
+ assert valkey_store._make_key("foo") == "LITESTAR:foo"
+
+
@pytest.mark.xdist_group("redis")
def test_redis_with_namespace(redis_store: RedisStore) -> None:
namespaced_test = redis_store.with_namespace("TEST")
@@ -239,12 +327,27 @@ def test_redis_with_namespace(redis_store: RedisStore) -> None:
assert namespaced_test._redis is redis_store._redis
+@pytest.mark.xdist_group("valkey")
+def test_valkey_with_namespace(valkey_store: ValkeyStore) -> None:
+ namespaced_test = valkey_store.with_namespace("TEST")
+ namespaced_test_foo = namespaced_test.with_namespace("FOO")
+ assert namespaced_test.namespace == "LITESTAR_TEST"
+ assert namespaced_test_foo.namespace == "LITESTAR_TEST_FOO"
+ assert namespaced_test._valkey is valkey_store._valkey
+
+
@pytest.mark.xdist_group("redis")
def test_redis_namespace_explicit_none(redis_client: Redis) -> None:
assert RedisStore.with_client(url="redis://127.0.0.1", namespace=None).namespace is None
assert RedisStore(redis=redis_client, namespace=None).namespace is None
+@pytest.mark.xdist_group("valkey")
+def test_valkey_namespace_explicit_none(valkey_client: Valkey) -> None:
+ assert ValkeyStore.with_client(url="redis://127.0.0.1", namespace=None).namespace is None
+ assert ValkeyStore(valkey=valkey_client, namespace=None).namespace is None
+
+
async def test_file_init_directory(file_store: FileStore) -> None:
shutil.rmtree(file_store.path)
await file_store.set("foo", b"bar")
@@ -280,7 +383,13 @@ def test_file_with_namespace_invalid_namespace_char(file_store: FileStore, inval
file_store.with_namespace(f"foo{invalid_char}")
-@pytest.fixture(params=[pytest.param("redis_store", marks=pytest.mark.xdist_group("redis")), "file_store"])
+@pytest.fixture(
+ params=[
+ pytest.param("redis_store", marks=pytest.mark.xdist_group("redis")),
+ pytest.param("valkey_store", marks=pytest.mark.xdist_group("valkey")),
+ "file_store",
+ ]
+)
def namespaced_store(request: FixtureRequest) -> NamespacedStore:
return cast("NamespacedStore", request.getfixturevalue(request.param))
@@ -393,3 +502,17 @@ async def test_redis_store_with_client_shutdown(redis_service: None) -> None:
for x in redis_store._redis.connection_pool._available_connections
+ list(redis_store._redis.connection_pool._in_use_connections)
)
+
+
+@pytest.mark.xdist_group("valkey")
+async def test_valkey_store_with_client_shutdown(valkey_service: None) -> None:
+ valkey_store = ValkeyStore.with_client(url="valkey://localhost:6381")
+ assert await valkey_store._valkey.ping()
+ # remove the private shutdown and the assert below fails
+ # the check on connection is a mimic of https://github.com/redis/redis-py/blob/d529c2ad8d2cf4dcfb41bfd93ea68cfefd81aa66/tests/test_asyncio/test_connection_pool.py#L35-L39
+ await valkey_store._shutdown()
+ assert not any(
+ x.is_connected
+ for x in valkey_store._valkey.connection_pool._available_connections
+ + list(valkey_store._valkey.connection_pool._in_use_connections)
+ )
diff --git a/uv.lock b/uv.lock
index 25bba1d003..20157cb2e5 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1628,6 +1628,122 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/0a/13/e37962a20f7051b2d6d286c3feb85754f9ea8c4cac302927971e910cc9f6/lazy_model-0.2.0-py3-none-any.whl", hash = "sha256:5a3241775c253e36d9069d236be8378288a93d4fc53805211fd152e04cc9c342", size = 13719 },
]
+[[package]]
+name = "libvalkey"
+version = "4.0.1"
+source = { registry = "https://pypi.org/simple" }
+sdist = { url = "https://files.pythonhosted.org/packages/38/49/57857ba9d02ba4df3bc1e71044f599c82ea590e928328e6b512dbf720228/libvalkey-4.0.1.tar.gz", hash = "sha256:fe60ef535bc826fc35f4019228a0a46bdce8b41fd6013a7591e822a8a17c3170", size = 109005 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/17/ac/c7b21f810c17527f77c8bd4145e21568a95a4eccc32bce8df4c5ba5d8863/libvalkey-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e180a893ac62e340a63e18c6dcc91fc756c9f2291b47b35ee1febec68c6d13c", size = 43044 },
+ { url = "https://files.pythonhosted.org/packages/e9/67/84c88cf0e8df1d68da9a2e7f6a79e818031a7ced1b70d66c60041e8dd7b5/libvalkey-4.0.1-cp310-cp310-macosx_11_0_universal2.whl", hash = "sha256:f51c08cae774071ea354658f9a9bb7ffb7b1743661011a28668650b130e0d063", size = 82094 },
+ { url = "https://files.pythonhosted.org/packages/7a/b3/4a7bf5a0275674cb17e0204c05e16356c94406256d811317e6ba87e1f234/libvalkey-4.0.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:98a37d1cb5f4c3dde6646968b0a624d3051fd99176583a5245641050e931a682", size = 44753 },
+ { url = "https://files.pythonhosted.org/packages/25/2f/aee00783de3ad3fbbadca23692f854f4b9f4b545c55db19657a4330e1bb4/libvalkey-4.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:01c4051c3b772bd3032ca66c96f229412622ef0bef344f9ad645221f56082573", size = 170126 },
+ { url = "https://files.pythonhosted.org/packages/1d/56/c8f80d3fa881cf79d20b537dcbc3ab5c8776db51cfa50b2a04a3191d027d/libvalkey-4.0.1-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf424fe1f45462ae4fea5f88b250ae86d7217a9662cfe5cd8a25208268129833", size = 165552 },
+ { url = "https://files.pythonhosted.org/packages/f1/0c/e697bc18740d95dd0a3104404a0fbaaf4f1d463ac6b7ed2f6fc0c8be4b6a/libvalkey-4.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea9bdd8fc54de6ceea9e28dc28b327a443423dd1d110bb9fa1d67f02626a8679", size = 181753 },
+ { url = "https://files.pythonhosted.org/packages/07/f6/49e0b1eb0cc9aee67d711386cbda604ea67752d17d9f94b62ea9866716af/libvalkey-4.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:641eed2e36408b8ba553c4606b2cfbee05286183249c76841188897d595c6639", size = 170657 },
+ { url = "https://files.pythonhosted.org/packages/b4/07/205b2e63936f880d0ff8cc7cc27059aa698a0d4f02dc9194854eadce985c/libvalkey-4.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dbf76b1b51bd5fe23dd09d0b7599cf6ee7a074e73a1933910e5faa1741408708", size = 170331 },
+ { url = "https://files.pythonhosted.org/packages/35/93/31734676641cb36a3ac23ffedc89b328a63a2f00eba80fc0554e2dd93872/libvalkey-4.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:75918faf78b2728ef8a73438361c328d70757cdb0e8bf57fa636e0776f302d4e", size = 164756 },
+ { url = "https://files.pythonhosted.org/packages/b7/fd/1f8476e45792c1bd6bb364e7f04c0274caa37767d4ed12658b1d863874cf/libvalkey-4.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:aa678090591e1c28a5f0647ce69531752e8f75e83a03e8963500941475898ccf", size = 162825 },
+ { url = "https://files.pythonhosted.org/packages/23/03/c293870a74b88d8ce2c5fed2a049eb2ec2373e29ccd3eb3df32217746e00/libvalkey-4.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a1eff0939e0577ddc6b8b359a846c0a83cb7ed3b0688fe98f8f8cf3ba8aa04b7", size = 176181 },
+ { url = "https://files.pythonhosted.org/packages/6e/b0/8624fa9195c4af93044860c9685b7667c1b7dd9bff6b62f815e65a512f24/libvalkey-4.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:b3ac608744fc2727eb87cdd7613f8d64b18a210b1661706d2b2de09fffd3d2d0", size = 167755 },
+ { url = "https://files.pythonhosted.org/packages/f6/66/74f722d90e37addf2b1235ce8294d50751c1a406a7dd05e7b4893f474daa/libvalkey-4.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e8801cf0274b2a6b0d19ea47de351e5ce67579b8503c4f9905ab53b52fbf270e", size = 165462 },
+ { url = "https://files.pythonhosted.org/packages/18/a1/16512251a897ad7022787ae395c2ecaf48449f7fce170d6656c5a27df795/libvalkey-4.0.1-cp310-cp310-win32.whl", hash = "sha256:a9438415f500c1b65fe258f102b004ef690db142a74d681d10fd82e344dc947f", size = 19468 },
+ { url = "https://files.pythonhosted.org/packages/5b/a8/7819672c42b470c67a994db05dd876b88ad97d5e4ae3152a7e49172b0b1b/libvalkey-4.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:cd3495a5c4c7f04c26bd5c34feb15c13da2dab5a349756a3f42f2a15521a5197", size = 21354 },
+ { url = "https://files.pythonhosted.org/packages/c4/7a/d7e4726c9a08c703fd4e824c7c644ae6c5f0ee3f1b99474a524f0149b77f/libvalkey-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f342da7200765da30e8a6a540722a8e9e689b0b0604e067290d308981d93826f", size = 43043 },
+ { url = "https://files.pythonhosted.org/packages/27/ae/30ba1da48e143da9c1fa0e4cf4899bbd4402b0a0c8f6c355aa76e89b6490/libvalkey-4.0.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:0db70261f8843007ea995f7adf0d619780380ac3abc4c1ac44ad4f3e885d5594", size = 82093 },
+ { url = "https://files.pythonhosted.org/packages/84/da/1c2b524ad44a7c24d7e62bb63d995bb8e59863c0f88844778c109604f83f/libvalkey-4.0.1-cp311-cp311-macosx_11_0_x86_64.whl", hash = "sha256:785c73ba7177777d9af01f48aa3344099815cdae3fef12c5d0f35b9b392f35bf", size = 44754 },
+ { url = "https://files.pythonhosted.org/packages/f7/1f/954f1ac80371dc50efaada4ca133219e2edb265c136c7fa2af1821caf5b2/libvalkey-4.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d56ed4c6c17bfb65bf4fe0745fdb3ae6bd1111af6171294497173e3a45226d7", size = 170152 },
+ { url = "https://files.pythonhosted.org/packages/cf/3f/1fbe055702041bcf2a85e056955219102e8b0aa3967482a5d68f7a3bb8c8/libvalkey-4.0.1-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d99b4adae993b9d8f057e150e5a2f938823d17286abcbc5cca0cb4741c530ddf", size = 165334 },
+ { url = "https://files.pythonhosted.org/packages/49/ad/ef273ef578fbac6e3b336c2138e457893654da0a40c75fcc76bf28be4761/libvalkey-4.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3d803812b4933a1926479aff4057f06b4332977b796038b4309d98546c56edf5", size = 181816 },
+ { url = "https://files.pythonhosted.org/packages/2e/87/3b681951477e98e135dee6f8b570779875a96a0367ad886327610f9134ee/libvalkey-4.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b473dc3d005a9b57e4445cb2a9ab48f8a26ea90889458ef3cb4d3dd7b23b5a26", size = 170687 },
+ { url = "https://files.pythonhosted.org/packages/13/4c/d384395d2378e6481cdcb1fb7c6e6d0a3ae0feb3dffaefbd6c1eb39cb3d1/libvalkey-4.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:195f7e78cb6d2c391dac2d0fc1bf7e65555ebad856e0c36bcc4986e0b3b6c616", size = 170453 },
+ { url = "https://files.pythonhosted.org/packages/8f/d8/1c64a5704ef4f843e2ffab8d815f1c918445f92e38660a6d44c7c64d1fe1/libvalkey-4.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:79b446abdb18aefc984214de68ac5f50164550a00b703b81c2b9d9c1618f4a13", size = 164803 },
+ { url = "https://files.pythonhosted.org/packages/e1/65/6d3004b011a799781f379bdba531a3c19bc5f8cd929bafa96fc066a59b12/libvalkey-4.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3453cd138a43cdcce32cbbbdc99d99472fb7905e56df8ff2f73dac5be70f0657", size = 162855 },
+ { url = "https://files.pythonhosted.org/packages/fb/b8/35c8f8cedfeaf2ddb261f09e9a618a3e5ce44c8d4ea29e19ce4c1ae175d7/libvalkey-4.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0a9acf658749ee324750643df040a62401d479de9a4507ca8f69bcf02df1b189", size = 176207 },
+ { url = "https://files.pythonhosted.org/packages/fd/ea/428c9404f41bce80d946ed904b5749a5b3ac2f2a6a1a48f4da1c9b58f8b2/libvalkey-4.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:ebfe6976a10ab6fb84d885622a39ff580803f3244a048b75fb63a97048cb894c", size = 167761 },
+ { url = "https://files.pythonhosted.org/packages/2f/97/b0e5fc755c78ac23a6e7a5c81288e7b44131becc11af07ef087f54054adf/libvalkey-4.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:860862322eceb3ed2ff2031663ee42d9ff4146226af3734f818b54a70339c440", size = 165463 },
+ { url = "https://files.pythonhosted.org/packages/c7/fd/9700a1edec4ebacbcb7ccdf55ac6548f2a5693b016768d721c0d520753ad/libvalkey-4.0.1-cp311-cp311-win32.whl", hash = "sha256:dd96985818cc1ddc8882dda67fa1cf711db37d0a24a4cd70897fd83a7377a11c", size = 19475 },
+ { url = "https://files.pythonhosted.org/packages/85/25/d59dbdf8cb16d5c1f9215fc7cf66d2cbca6d05008eda1104b321df785647/libvalkey-4.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:4a1174d53d949f38128efc038b2d77cb79c4db127f5707ad350de0cda3aa9451", size = 21358 },
+ { url = "https://files.pythonhosted.org/packages/2b/62/fb85f94411890d233c74aad7b581bb65a0f809b5757446a280a8fa42a50d/libvalkey-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3d5da92598f8e6a82a5e3dedd49dae39fce6b3089030e17681e2b73df4a6d89", size = 43057 },
+ { url = "https://files.pythonhosted.org/packages/ed/cb/6f7614cab744f0e4e0eae583b2997bf22ffee4aa333e26786b91342986b6/libvalkey-4.0.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:ce623bb8c37beb16d0f2c7c5b7080a3172dae4030e3bcd71326c7731883f766f", size = 82198 },
+ { url = "https://files.pythonhosted.org/packages/cf/de/9515ba0f436c3e54331b66cf7652c03fc73688e0b6f22853a6fc2cc8aa23/libvalkey-4.0.1-cp312-cp312-macosx_11_0_x86_64.whl", hash = "sha256:00adc978a791e944e2f6b442212cd3494a8d683ed215ff785dc9384968b212b6", size = 44839 },
+ { url = "https://files.pythonhosted.org/packages/21/f1/dd28a89f6c89e4fbcd95be18a04758f6f57fc69d38a7bc22a59377b277fc/libvalkey-4.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:827ea20b5ee1d99cf3d2c10da24c356c55836dd6ff1689b3fbf190b5bffe1605", size = 173314 },
+ { url = "https://files.pythonhosted.org/packages/c6/17/debc72596eb3e4c27a4ae1a5b5636e99b7b5e606c072c8816358ab69fb7f/libvalkey-4.0.1-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f81f7d806e5dd826532c0a4b6d8bc91a485fba65a3767cfdeb796b493ac59c8c", size = 167968 },
+ { url = "https://files.pythonhosted.org/packages/fd/00/451b234f5125e0b9396d7ca4b9d2ab9785e21475f4da60ff019e48912f73/libvalkey-4.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:65fe45323bbabee8d770127c0a763182a0d540a8c1afe6537d97dcc021fc26c4", size = 184371 },
+ { url = "https://files.pythonhosted.org/packages/09/c1/e10266e11034af9194feacec78221bb01db6961b662303a980c77a61f159/libvalkey-4.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c20ec7a26163dad23b0dfdbb81dd13ae3aa4083942b438c07dadaed88fa0ca6c", size = 173422 },
+ { url = "https://files.pythonhosted.org/packages/88/ba/fe3b25281e41546ea96c41b7899d2a83a262463432280e07daed44beb7f5/libvalkey-4.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c0d5b4b01c2e4e5bad8339d8b585f42c0b10fb05a6e4469c15c43d925be6285", size = 173617 },
+ { url = "https://files.pythonhosted.org/packages/05/b8/a75b6edcaabdc6245ee719357d307e2fccb375ca09d012327fbc1ef68771/libvalkey-4.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c151a43b250b6e6412c5b0a75093c49d248bbe541db91d2d7f04fd523ea616b3", size = 167110 },
+ { url = "https://files.pythonhosted.org/packages/a9/ae/602254b8865a0fb21df3f3cd57815ca7e6049cd79318bfb426449b661cee/libvalkey-4.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c8f59bb57f8e02e287da54a2e1250b9d591131922c006b873e5e2cad50fc36c", size = 164932 },
+ { url = "https://files.pythonhosted.org/packages/0f/c6/116f5432c8234630079f3dadcf48828db41c2bfcdfaeb36ef197a2efa380/libvalkey-4.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:89e79fade6e6953c786b0e2d255a2930733f5d9e7ef07cf47a4eb0db4eabba5e", size = 178905 },
+ { url = "https://files.pythonhosted.org/packages/ce/00/ec095e022b7e5c2035787ad7389e0a11157ceb98f4ceae7fc44805907be0/libvalkey-4.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:56495ab791f539dc3ee30378f9783f017e000ad8b03751ad2426003f74eee0bc", size = 170350 },
+ { url = "https://files.pythonhosted.org/packages/a5/84/d8bd771b07854c58cbf8926d98fed1701a4dcbe97ef31e8fea63416fc461/libvalkey-4.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:df9d7ba691c49c632bdc953b5c0af5c50231d0ae3bb0397688f63257a12786c0", size = 168125 },
+ { url = "https://files.pythonhosted.org/packages/45/88/00d5d2d0960d0023c52d25d5ae87d47b5aec995241788be5c424826727aa/libvalkey-4.0.1-cp312-cp312-win32.whl", hash = "sha256:a39ad585b3d2d48d6f5b60941f9d6a5f3f30a396ae129db15bf626316f71594f", size = 19651 },
+ { url = "https://files.pythonhosted.org/packages/8f/57/a3f837524d63ed927f6ab3da3be2050f6c838279c796d5b44b617cad0047/libvalkey-4.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:7b39754c9cdf7fe704c636a2ea179c17229566e7c79af453df3a604b98879dc3", size = 21451 },
+ { url = "https://files.pythonhosted.org/packages/51/3c/8571abc9b8a78281312b99348bccb35dfa161a3a3e9b963afdd473beea40/libvalkey-4.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f72346eca7408cfd6d6f407e7e548040b310ed6fdaec7d9ea67b49f20dc90a9e", size = 43065 },
+ { url = "https://files.pythonhosted.org/packages/8e/08/197217ff273fde5670b84682a2d67fe372890d14595ae0a15284626975ba/libvalkey-4.0.1-cp313-cp313-macosx_11_0_universal2.whl", hash = "sha256:66b4558ca5b8fa48fde40dfc79547779d78c5397906f5ea5671b9a75f0952ff4", size = 82206 },
+ { url = "https://files.pythonhosted.org/packages/51/e1/a806533c315cf758812e4f609548ccbb51c10221e2a3c6f9aa6e17633ee9/libvalkey-4.0.1-cp313-cp313-macosx_11_0_x86_64.whl", hash = "sha256:33d29f8d826b59e972a8502e8547d5fef7b1a1376fa0884cf1360c15977bca50", size = 44840 },
+ { url = "https://files.pythonhosted.org/packages/7b/c8/9908fdb4a5661bef8972cf94d149f5c5199c3835bba1a6f523225e2d6c37/libvalkey-4.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8adea3c5824937c1e94bb1d5bc30c57661e8bbcb1a79e8ead77b45bbe206f488", size = 173200 },
+ { url = "https://files.pythonhosted.org/packages/80/d2/3b6c235393137b16dacddb04ac6b632f3998cd10cb52b1e34b2eb7bdcabf/libvalkey-4.0.1-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:50e956e1bc0ab21e2479fb5729456ae74de808a1be799b9163bf7a25029eeb41", size = 168270 },
+ { url = "https://files.pythonhosted.org/packages/79/b3/844123ae52d63d9ec97f4ad026054a0b616d83fd886adcfd2f8484939044/libvalkey-4.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:56d6db545639a5fbb1c634621634a7f87845b7867056b1460a8299cc489e3364", size = 184290 },
+ { url = "https://files.pythonhosted.org/packages/7c/13/390d1f1fac2167e5e4531cbc090ec99e974271fc05e4c0c8597db593596d/libvalkey-4.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b83e133826ca50506c9f49b5c4fd64ef0dc3bbc6e85bb18b781a08320bf3f0db", size = 173279 },
+ { url = "https://files.pythonhosted.org/packages/6c/9f/74deb4ea77efb2cbf24c2a7364628b93f3bd02bff7203162c88e9bfe8f13/libvalkey-4.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e58b6dcea57df7ee8d80f914ed8895141fbb53d6f344b310ebe6cae3e407d0f", size = 173436 },
+ { url = "https://files.pythonhosted.org/packages/db/e6/9bb87d6d2fe4ba4da960104356c2b165766cb1d420ef1d7f0f671729f3ab/libvalkey-4.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:35576248ac379e755cf40c4ebe6bf735f278d46b5e449d0c8ea9f66869e3a8d4", size = 167050 },
+ { url = "https://files.pythonhosted.org/packages/2e/aa/35eda3faa3a7e9a5702c1833cf2ff0fdb024661d8342b24393198db968a2/libvalkey-4.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2be9cd8533638be94956567602554bbffa65d6fc8e758cd628f317a58cbcafda", size = 164934 },
+ { url = "https://files.pythonhosted.org/packages/ba/54/6439403407317d1228f8b2d5e38917ff162cd86b371bf28953e727674b20/libvalkey-4.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a03058988844b5a56f296d0d5608bbbe38df1b875246d6c6d7b442af793b5197", size = 178943 },
+ { url = "https://files.pythonhosted.org/packages/f5/54/8628c445f9683d2b0f2df3cf2084ec48917d33ccf3f857b2b4b25c6ba3a8/libvalkey-4.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:885a2ca644a2fdaf555e9fdab2bbe7de0f91de4e2a07726751efa35417736d55", size = 170398 },
+ { url = "https://files.pythonhosted.org/packages/e1/86/9780ad4d818fbb63efb3763041109fbdbe20a901413effa70a8fcf0ec56b/libvalkey-4.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:90fb5252391a8a9a3bb2a4eadd3f24a8af1032821d818e620da16854fb52503e", size = 168104 },
+ { url = "https://files.pythonhosted.org/packages/61/b2/8ec653c1e1cb85a8135f6413be90e40c1d3c6732f5933f4d3990f1777d09/libvalkey-4.0.1-cp313-cp313-win32.whl", hash = "sha256:ac6d515ece9c769ce8a0692fcb0d2ceeb5a71503a7db0cbfef0c255b5fb56b19", size = 19657 },
+ { url = "https://files.pythonhosted.org/packages/61/92/f0b490a7bd7749aeed9e0dfca1f73e860a82ccb3ddb729591e4324c54367/libvalkey-4.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:125ff9fdba066a97e4bbdea69649184a5f5fcb832106bbaca81b80ff8dbee55c", size = 21461 },
+ { url = "https://files.pythonhosted.org/packages/eb/9b/16cf35d50004c918da27cd9f33e27a1037690b523e8d4e8244b497988d8a/libvalkey-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9f389b48f37e7d14fd42eb47e52b799c1624edafc2b9398b9fe2f4e204d072a4", size = 43052 },
+ { url = "https://files.pythonhosted.org/packages/f6/19/865dc1a17f8a4b4f5c63cb926bf30cfff61c69446b27f83a9c7b8da65d5e/libvalkey-4.0.1-cp38-cp38-macosx_11_0_universal2.whl", hash = "sha256:200b135258f6ada4aaacf8499e2d2d3484b39a03b2178f64d4da16eb39bcbf77", size = 82130 },
+ { url = "https://files.pythonhosted.org/packages/b4/03/c12e79b6dfc1d9f90315288bf81e7c4df5ddbfeb22ade52c61d5eacb93ec/libvalkey-4.0.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:4aaa2b8ef0a3cc1a72abbb29667be2321ea5cd31f3b131ea0a35e4ee86caea6f", size = 44774 },
+ { url = "https://files.pythonhosted.org/packages/d7/84/c6fa981a5a922dccf2c6eebb0d9cad3fbb3122c7d21ad3d9f444f67cc97f/libvalkey-4.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:91143449ee77ca072799759469df20ff538b82e0c538e3f3a4afbe5f1c7bfeaf", size = 172594 },
+ { url = "https://files.pythonhosted.org/packages/ad/28/e1745166d26c73cb7a6fa1df5f51f0326a4e7e79fd8a9948f81a750132e9/libvalkey-4.0.1-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e266a71b747cf5f8c8882966c58c080a61f8cb772bbf6dbb2d67530034ebd611", size = 167113 },
+ { url = "https://files.pythonhosted.org/packages/b1/4e/61c0b3392f8f97bc169c3f9eaee8053ec514e3ee85ed3fea0b3ee0cc6072/libvalkey-4.0.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f9bb157a7fdc91b49d274eeb7961fcdb03d32380d1c25b9bcbb4dd490944539e", size = 183759 },
+ { url = "https://files.pythonhosted.org/packages/e5/d0/43c41bbbbc05e781396508ad689e3b5507701ba3c57da204bee0486bfb3b/libvalkey-4.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:be5dae7eebe303f549b9cab63fb9d6b1a1730b00e5011b0cb3d3403dc2d70ad9", size = 172950 },
+ { url = "https://files.pythonhosted.org/packages/80/3e/1a03a45f9dfbb634da3db90ec96c92df56fa1a844cbd7a479f790e6b513f/libvalkey-4.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:60466c4bfd4d55ce6233d951627a4eacdae6888de0885695b5b6f3deafde57bf", size = 172691 },
+ { url = "https://files.pythonhosted.org/packages/3c/2f/65e4a05ed217f5e59a5677c5c7fea110f3a343349f0c1b8425132f4a285c/libvalkey-4.0.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:f448af77c485fabb2f93928ca759f9813bc8999f2fb0560d9c2e4870aa6e0edc", size = 165533 },
+ { url = "https://files.pythonhosted.org/packages/16/6a/4cb7e3770694029c8289e041734f96b0d0203a36d6330bc1276979815191/libvalkey-4.0.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:cc4354d075614a736e62d8283fe173df66e55b5260e6c29ff851a1d3680a5d1e", size = 163574 },
+ { url = "https://files.pythonhosted.org/packages/26/b7/d49605d0e0a0f998f9addf724fd20ac2142bbb3c714e80f34406d7cee1fc/libvalkey-4.0.1-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:6445163e102f10217532b6547edcc239f2dd0bced13fd982da10b352d0771b21", size = 176969 },
+ { url = "https://files.pythonhosted.org/packages/ad/04/876ea16da27d5000d6b4d763a0fa0b43a06fb4e45b70acb70f12eeef3f84/libvalkey-4.0.1-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:aa162ddb08a5d9a3b2d08f6ebe92385a049077c9b4e168e5171c615fbc8155b8", size = 168622 },
+ { url = "https://files.pythonhosted.org/packages/2b/4d/e208e3335988ae2d35ca07f9e7b4718ccc2c0eef7e50ca6c4149c37c37df/libvalkey-4.0.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:48cc9f0fd6724780949bddbbadda9ee338b63a8923202bd7df0e2de4feea63bf", size = 166221 },
+ { url = "https://files.pythonhosted.org/packages/2b/81/828b1db1fb2dbcda215bb3806b89d2493e6c4a7ab4b529c7bcbdc6e1cc96/libvalkey-4.0.1-cp38-cp38-win32.whl", hash = "sha256:471ac81196e1bf5d00069be2bc6fee4f52744b0a3c219b51f3d3115a7903e190", size = 19490 },
+ { url = "https://files.pythonhosted.org/packages/7f/a8/c34155613194fa9cbf406dd0cb05b965b8280c52d00af12062ddb609b711/libvalkey-4.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:3ff7f2e78c0e195d862cb9bda3b3fe16183713220d5f2faae653d9b187249c9b", size = 21368 },
+ { url = "https://files.pythonhosted.org/packages/ce/17/d432510a70089a9781b81dd94d649d156f8af9db0c8b9603702b0ec95dcc/libvalkey-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e9c5975aae213a3c7251c3e8989c78b2ee39be5eace45a7d99fadc6a4a5a7bc4", size = 43036 },
+ { url = "https://files.pythonhosted.org/packages/49/88/64f54ed1ce28fc1c27353ff676b8673820384af72bafa12930566c0d8843/libvalkey-4.0.1-cp39-cp39-macosx_11_0_universal2.whl", hash = "sha256:c3ce037eeb03682c1dea8435bc0b9c118dba105cd8dca353b4a49cd741fff60f", size = 82089 },
+ { url = "https://files.pythonhosted.org/packages/e4/2c/a64b3aa6fceb32026f965d983251b59a30017dd973c243ed0050400cebba/libvalkey-4.0.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:d9ff6deda50245842b901501e282be0399fd6c5289ae9f7a6cc5c62a2e5303d7", size = 44751 },
+ { url = "https://files.pythonhosted.org/packages/a0/9a/aa4cc4075fa05d98607011efd98888bf7e9eb9c7278bc9e3ea14206cc3e8/libvalkey-4.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd77106af55d6c0fb588fe58c2daea2ccf05ffab3713266b66157add022b9623", size = 169574 },
+ { url = "https://files.pythonhosted.org/packages/bd/7c/870dc7b68a0166bc216c403157e25fdd29e34ed1429b6821903cac31ad81/libvalkey-4.0.1-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff5e5559b3aa04f1cd630b07f320ff0bd336471e5c74ef27a30e198b1a35b7c8", size = 164870 },
+ { url = "https://files.pythonhosted.org/packages/87/6c/525d00c790cfae5fc196d2518de878e15d4b54459dc71aed5137e8bf6282/libvalkey-4.0.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:70deceeb55973d6b5911b06f7ceadeea022a2496a75aa9774453f68b70ab924b", size = 181172 },
+ { url = "https://files.pythonhosted.org/packages/b0/b6/b0e6a1f509a6a11b3f925038d4e3d0fd9da18d56d3be34ed41b8a44d6c8b/libvalkey-4.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ce6b42ab06ba28d7fc8d24b8da9eccda4033e9342b6d4731c823998ec0294a09", size = 170052 },
+ { url = "https://files.pythonhosted.org/packages/ca/c0/bcedb0f40ee4d12694f3c7d6809d7de8b8205636fe291f1b7daf6094d8cc/libvalkey-4.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c38f42b6632fdfd39c0e361d004c0c93f9059b6c3b36626f903a371abbb8af8b", size = 169800 },
+ { url = "https://files.pythonhosted.org/packages/57/2e/40dfde852a9dde4baf961531a294d02152d89c4bbd7fc72ccf798c92b951/libvalkey-4.0.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d2175fd547761e67f00141b7d22ea6ba730da6ae72f182b92d122ed6b9371f27", size = 164293 },
+ { url = "https://files.pythonhosted.org/packages/b7/4f/34c6bd1097b33cc0eeeb514b0992639f6e5df9edf86d424d9ffc09dd6d32/libvalkey-4.0.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:13856099dd591714975ee4399f1c6a1b87d4a7a79960681b641b57ee70bcc5a3", size = 162324 },
+ { url = "https://files.pythonhosted.org/packages/83/a8/31fd517128120e4df4aa0209519ac6a467d38ecbc898dae9100a1f288ac7/libvalkey-4.0.1-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:fa4dc913f28d799e755fbf2bd411bc0e2f342b9a4cdc2336aab68419b405e17d", size = 175654 },
+ { url = "https://files.pythonhosted.org/packages/8d/f6/b46976335a946e3f3c1cfe8155bcb2b3ad0b6496ec87a8ca90f4da561a56/libvalkey-4.0.1-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:be54d0ce94ff65ff8eede2ab78635e0f582f27db3e9143a1e132910896157684", size = 167234 },
+ { url = "https://files.pythonhosted.org/packages/3b/08/df3cdaed3bcd15a9470fbb2511de9b3237e3b956a1c8d835b75ff1d56c0e/libvalkey-4.0.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:6c7500ddd11760372c3d9ace0efea0cf00834857be7f7da6321ba9a0ba01379f", size = 164994 },
+ { url = "https://files.pythonhosted.org/packages/ff/6b/7342449b847165e773ccf320189161ec26663dbc93fcc5099539a270ae09/libvalkey-4.0.1-cp39-cp39-win32.whl", hash = "sha256:e5b7cf073a416f2be03b6aebe19d626f36a1350da9170dc2947d8364a77d6c3d", size = 19489 },
+ { url = "https://files.pythonhosted.org/packages/cd/9d/64a33e7141ef8cb63078a3b3e4e4821adfff401198cfa536679ca78e0247/libvalkey-4.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:d050e7ac0906fc1650c5675b0a68da53181425937986559d129da665382e444a", size = 21367 },
+ { url = "https://files.pythonhosted.org/packages/39/7d/8dec58f9f2f0f4eb8b1b861a4ee5ef2c8e7b63a46f0ffbba274f5170125b/libvalkey-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:75528a996263e57880d12a5b1421d90f3b63d8f65e1229af02075079ba17be0a", size = 37210 },
+ { url = "https://files.pythonhosted.org/packages/77/d9/857376c3e0af4988d1b8ad13e8ee964dcfae9860e1917febd4f6b0819feb/libvalkey-4.0.1-pp310-pypy310_pp73-macosx_11_0_x86_64.whl", hash = "sha256:4ee4f42a117cc172286f3180fdd2db9d74e7d3f28f97466e29d69e7c126eb084", size = 39638 },
+ { url = "https://files.pythonhosted.org/packages/c2/ae/9c0fcf578a56d860a9e056e67fbdff54b33952a88b63c384bc05b0cfe215/libvalkey-4.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb120643254a1b44fee2d07a9cb2eef80e65635ac6cd82af7c76b4c09941575e", size = 48760 },
+ { url = "https://files.pythonhosted.org/packages/ff/3d/76fa39c775c33e356be5b7b687b85d7fea512e1fd314a17b75f143e85b67/libvalkey-4.0.1-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e62c472774dd38d9e5809d4bea07ec6309a088e2102ddce8beef5a3e0d68b76", size = 56262 },
+ { url = "https://files.pythonhosted.org/packages/5a/cb/60131ef56e5152829c834c9c55cc5facb0a1988ba909c23d43f13bb65e0d/libvalkey-4.0.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a73ce687cda35c1a07c24bfb09b3b877c3d74837b59674cded032d03d12c1e55", size = 48920 },
+ { url = "https://files.pythonhosted.org/packages/e8/ac/69d01a8e2ad5c94bd261784b8e8c2be3992b48492009baf56fcd16d1ab15/libvalkey-4.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:1cd593e96281b80f5831292b9befe631a88415c68ad0748fe3d69101a093c501", size = 21366 },
+ { url = "https://files.pythonhosted.org/packages/28/15/39c3c69ee642ea1271be2c92ca8e628e251b898d98306953b70a37d46310/libvalkey-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:a50f5f7482aa64038aa93ba12c45bffd2950a5485288558adc80ebc409b20a21", size = 37244 },
+ { url = "https://files.pythonhosted.org/packages/92/82/8801ecc1d4f875b7f218cc6ad9345cf7ef3c0e9eec2ada6c7fc34b6c5609/libvalkey-4.0.1-pp38-pypy38_pp73-macosx_11_0_x86_64.whl", hash = "sha256:bda1b59ed326fc0fe909b4be38297d37cba1ee332913f1ab1a8f17bd9791e2c9", size = 39663 },
+ { url = "https://files.pythonhosted.org/packages/ab/a7/0458e8387f860c96c64242c8c78118d228a54a619a64b59d918c5a44bdf6/libvalkey-4.0.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f111810607172cada546003d444e9f0d7b2c9d1a5f305e56d365bda89adbce8d", size = 48790 },
+ { url = "https://files.pythonhosted.org/packages/26/d6/e79606ad905d9ef0df36b5a4c3d933636467eef4f16dcbc719a6800de02d/libvalkey-4.0.1-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a2cf10a178140e94116ba467c209d38bc73962211a666e5b85e018194dd3c67e", size = 56353 },
+ { url = "https://files.pythonhosted.org/packages/cb/a9/c62cfa984c864088c22d9b326abdfd83b561d28f8f2eaf9863e6189d3349/libvalkey-4.0.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c1b982292085c1b14b487d348b6dd572a1e2cf9b892b96bae8b74d21304f4e4", size = 48991 },
+ { url = "https://files.pythonhosted.org/packages/c7/8e/322f5eedf6b9e14fa6b9749197b9f8a486736fa29b1b42f26ef0f7e5497c/libvalkey-4.0.1-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:3a5f27e938173df8dda85c7f76d0f92cfb8a5a6f59ac094da133e70bd5526ccf", size = 21380 },
+ { url = "https://files.pythonhosted.org/packages/03/86/f6e93a4f19df53f381d66bcd8ef9aa256c660d0eb924e58b0fdccec250b5/libvalkey-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:55a5b78467c0605817e12469630e627c3cccccb44ff810c4943337fbf3979529", size = 37185 },
+ { url = "https://files.pythonhosted.org/packages/68/c1/cc3658e45979a9cfe0e03df32b863a9ed75d1cedbc12147644ba6e4c406a/libvalkey-4.0.1-pp39-pypy39_pp73-macosx_11_0_x86_64.whl", hash = "sha256:af5a237ed6fec3c9977dd57248f11d9ab71a2d8a8954eb76f65171b7454f9f23", size = 39605 },
+ { url = "https://files.pythonhosted.org/packages/76/37/4e13d72109f2e946f9d472b6e9564c332a983d20ef1c1ddc54794d02dc17/libvalkey-4.0.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5ce282d3b888bbabb71eb065defb66383f0775fb1f12da42edfff1800d85336", size = 48703 },
+ { url = "https://files.pythonhosted.org/packages/2f/3c/76bfbca61ca46414c2c59a8006a88f04f8653c99a2f41ccc1b0663a8c005/libvalkey-4.0.1-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c2feb0686f51def52095d3429404db5092efb1edb336a961acc4887389c177a", size = 56226 },
+ { url = "https://files.pythonhosted.org/packages/29/bb/f245b3b517b9ca1f41a4e3dc3600fdec3c59765d18c1ca079de44b3e0f6e/libvalkey-4.0.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:30b9048d4f3745ecaa7e82aa985dbe57b8f96c6f5586767b9afd63d1c3021295", size = 48891 },
+ { url = "https://files.pythonhosted.org/packages/2a/54/c256395784535d31cf398f5a32a4fc2dac31003c28491fe7868e3ea07cd5/libvalkey-4.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2e321a8af5ea12281898744f41cf7f8c4008770dcc12f8f0afbc5f0b3cd40c4f", size = 21367 },
+]
+
[[package]]
name = "litestar"
version = "2.13.0"
@@ -1691,6 +1807,7 @@ full = [
{ name = "structlog" },
{ name = "uvicorn", extra = ["standard"] },
{ name = "uvloop", marker = "sys_platform != 'win32'" },
+ { name = "valkey", extra = ["libvalkey"] },
]
jinja = [
{ name = "jinja2" },
@@ -1738,6 +1855,9 @@ standard = [
structlog = [
{ name = "structlog" },
]
+valkey = [
+ { name = "valkey", extra = ["libvalkey"] },
+]
[package.dev-dependencies]
dev = [
@@ -1818,7 +1938,7 @@ requires-dist = [
{ name = "jinja2", marker = "extra == 'standard'" },
{ name = "jsbeautifier", marker = "extra == 'cli'" },
{ name = "jsbeautifier", marker = "extra == 'standard'" },
- { name = "litestar", extras = ["annotated-types", "attrs", "brotli", "cli", "cryptography", "jinja", "jwt", "mako", "minijinja", "opentelemetry", "piccolo", "picologging", "prometheus", "pydantic", "redis", "sqlalchemy", "standard", "structlog"], marker = "extra == 'full'" },
+ { name = "litestar", extras = ["annotated-types", "attrs", "brotli", "cli", "cryptography", "jinja", "jwt", "mako", "minijinja", "opentelemetry", "piccolo", "picologging", "prometheus", "pydantic", "redis", "sqlalchemy", "standard", "structlog", "valkey"], marker = "extra == 'full'" },
{ name = "litestar-htmx", specifier = ">=0.4.0" },
{ name = "mako", marker = "extra == 'mako'", specifier = ">=1.2.4" },
{ name = "minijinja", marker = "extra == 'minijinja'", specifier = ">=1.0.0" },
@@ -1843,6 +1963,7 @@ requires-dist = [
{ name = "uvicorn", extras = ["standard"], marker = "extra == 'standard'" },
{ name = "uvloop", marker = "sys_platform != 'win32' and extra == 'cli'", specifier = ">=0.18.0" },
{ name = "uvloop", marker = "sys_platform != 'win32' and extra == 'standard'", specifier = ">=0.18.0" },
+ { name = "valkey", extras = ["libvalkey"], marker = "extra == 'valkey'", specifier = ">=6.0.2" },
]
[package.metadata.requires-dev]
@@ -3870,7 +3991,7 @@ name = "taskgroup"
version = "0.0.0a4"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "exceptiongroup" },
+ { name = "exceptiongroup", marker = "python_full_version < '3.13'" },
]
sdist = { url = "https://files.pythonhosted.org/packages/0a/40/02753c40fa30dfdde7567c1daeefbf957dcf8c99e6534a80afb438adf07e/taskgroup-0.0.0a4.tar.gz", hash = "sha256:eb08902d221e27661950f2a0320ddf3f939f579279996f81fe30779bca3a159c", size = 8553 }
wheels = [
@@ -4297,6 +4418,23 @@ wheels = [
{ url = "https://files.pythonhosted.org/packages/1a/5c/6ba221bb60f1e6474474102e17e38612ec7a06dc320e22b687ab563d877f/uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff", size = 3804696 },
]
+[[package]]
+name = "valkey"
+version = "6.0.2"
+source = { registry = "https://pypi.org/simple" }
+dependencies = [
+ { name = "async-timeout", marker = "python_full_version < '3.12'" },
+]
+sdist = { url = "https://files.pythonhosted.org/packages/45/f7/b552b7a67017e6233cd8a3b783ce8c4b548e29df98daedd7fb4c4c2cc8f8/valkey-6.0.2.tar.gz", hash = "sha256:dc2e91512b82d1da0b91ab0cdbd8c97c0c0250281728cb32f9398760df9caeae", size = 4602149 }
+wheels = [
+ { url = "https://files.pythonhosted.org/packages/d7/cb/b1eac0fe9cbdbba0a5cf189f5778fe54ba7d7c9f26c2f62ca8d759b38f52/valkey-6.0.2-py3-none-any.whl", hash = "sha256:dbbdd65439ee0dc5689502c54f1899504cc7268e85cb7fe8935f062178ff5805", size = 260101 },
+]
+
+[package.optional-dependencies]
+libvalkey = [
+ { name = "libvalkey" },
+]
+
[[package]]
name = "virtualenv"
version = "20.28.0"