Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Fixed

- **Every fresh install broke on the first query (`redis` 8.1.0)** — the
SDK imports `redis.asyncio` directly but never declared `redis` as a
dependency, so pip took `falkordb`'s `redis>=7.1.0` range and resolved
to the newest release. redis 8.1.0 injects an internal
`himport_registry` key into `ConnectionPool.connection_kwargs`, which
`falkordb`'s `Is_Cluster()` forwards verbatim to the synchronous
`redis.Redis()` constructor — raising
`TypeError: Redis.__init__() got an unexpected keyword argument
'himport_registry'`, surfaced as `DatabaseUnavailableError`. `ping()`
still succeeded, so health checks passed and the failure only appeared
on real work. `redis` is now declared explicitly as `>=7.2,<8.1`. The
lower bound is a second fix: `falkordb` 1.6 imports
`redis.driver_info`, which does not exist before redis 7.2, so its
declared `>=7.1.0` floor was also unusable.

## [1.4.0] - 2026-08-10

Chunk-level extraction cache for `update()` (#288): re-ingesting a
Expand Down
7 changes: 7 additions & 0 deletions graphrag_sdk/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,13 @@ classifiers = [
dependencies = [
"pydantic>=2.0,<3.0",
"falkordb>=1.0,<2",
# We import redis.asyncio directly, so pin it explicitly rather than
# inheriting falkordb's range. Upper bound: redis 8.1 injects
# "himport_registry" into ConnectionPool.connection_kwargs, which
# falkordb's Is_Cluster() forwards to the sync redis.Redis() constructor
# -> TypeError on the first query. Lower bound: falkordb 1.6 imports
# redis.driver_info, which only exists from redis 7.2 on.
"redis>=7.2,<8.1",
"numpy>=1.24,<3",
"python-dotenv>=1.0",
"tiktoken>=0.5,<1.0",
Expand Down
34 changes: 34 additions & 0 deletions graphrag_sdk/tests/test_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,3 +322,37 @@ async def test_ping_reports_unreachable_instead_of_raising(self):
patch("falkordb.asyncio.FalkorDB") as mock_falkor:
mock_falkor.side_effect = RedisConnectionError("Connection refused")
assert await conn.ping() is False


class TestRedisVersionCompat:
"""Guards the redis-py range declared in pyproject.toml.

falkordb's ``Is_Cluster()`` copies ``pool.connection_kwargs`` off the
async pool and hands them straight to the *synchronous*
``redis.Redis()`` constructor. Any key redis-py adds to its async pool
kwargs but does not accept on ``Redis.__init__`` therefore breaks the
first query with a TypeError. redis 8.1.0 did exactly that with
``himport_registry``, so assert the invariant rather than the version
number — this fails on any future release that reintroduces the shape.
"""

def _pool_kwargs(self, cfg: ConnectionConfig) -> dict:
"""Build the pool the way _ensure_client() does, capturing its kwargs."""
conn = FalkorDBConnection(cfg)
with patch("falkordb.asyncio.FalkorDB", side_effect=RuntimeError("stop after pool")):
with pytest.raises(Exception):
conn._ensure_client()
assert conn._pool is not None, "pool was not constructed"
return conn._pool.connection_kwargs.copy()

@pytest.mark.parametrize("ssl", [False, True])
def test_sync_redis_accepts_async_pool_kwargs(self, ssl):
import redis as sync_redis
import redis.asyncio as async_redis

kwargs = self._pool_kwargs(ConnectionConfig(ssl=ssl))
# Mirror Is_Cluster()'s own fixups.
kwargs["ssl"] = kwargs.pop("connection_class", None) is async_redis.SSLConnection

# Constructing does not open a socket, so no live server is needed.
sync_redis.Redis(**kwargs)