Skip to content

Commit ff68117

Browse files
committed
fix(types): resolve mypy errors from redis-py incorrect type annotations
The redis-py library has incorrect type annotations for JSON commands: - `json().get()` is typed as returning `List[JsonType]` but returns `JsonType` - Async `json().set()`/`json().get()` are typed as non-awaitable These typing issues manifest differently across Python versions (3.10-3.13), causing CI failures while passing locally. Changes: - Disable `warn_unused_ignores` in mypy config for cross-version compatibility - Add `cast()` for `json().get()` results where dict access is needed - Add `# type: ignore[misc]` for async JSON operations
1 parent 7a57493 commit ff68117

File tree

6 files changed

+13
-11
lines changed

6 files changed

+13
-11
lines changed

langgraph/checkpoint/redis/aio.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1063,7 +1063,7 @@ async def aput(
10631063

10641064
if self.cluster_mode:
10651065
# For cluster mode, execute operation directly
1066-
await self._redis.json().set(
1066+
await self._redis.json().set( # type: ignore[misc]
10671067
checkpoint_key, "$", checkpoint_data
10681068
)
10691069
else:
@@ -1146,7 +1146,7 @@ async def aput_writes(
11461146
)
11471147

11481148
# Redis JSON.SET is an UPSERT by default
1149-
await self._redis.json().set(key, "$", cast(Any, write_obj))
1149+
await self._redis.json().set(key, "$", cast(Any, write_obj)) # type: ignore[misc]
11501150
created_keys.append(key)
11511151

11521152
# Apply TTL to newly created keys
@@ -1304,14 +1304,14 @@ async def aput_writes(
13041304
# Update has_writes flag separately for older Redis
13051305
if checkpoint_key:
13061306
try:
1307-
checkpoint_data = await self._redis.json().get(
1307+
checkpoint_data = await self._redis.json().get( # type: ignore[misc]
13081308
checkpoint_key
13091309
)
13101310
if isinstance(
13111311
checkpoint_data, dict
13121312
) and not checkpoint_data.get("has_writes"):
13131313
checkpoint_data["has_writes"] = True
1314-
await self._redis.json().set(
1314+
await self._redis.json().set( # type: ignore[misc]
13151315
checkpoint_key, "$", checkpoint_data
13161316
)
13171317
except Exception:
@@ -1479,7 +1479,7 @@ async def aget_channel_values(
14791479
)
14801480

14811481
# Single JSON.GET operation to retrieve checkpoint with inline channel_values
1482-
checkpoint_data = await self._redis.json().get(checkpoint_key, "$.checkpoint")
1482+
checkpoint_data = await self._redis.json().get(checkpoint_key, "$.checkpoint") # type: ignore[misc]
14831483

14841484
if not checkpoint_data:
14851485
return {}

langgraph/checkpoint/redis/ashallow.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ async def aget_tuple(self, config: RunnableConfig) -> Optional[CheckpointTuple]:
365365
)
366366

367367
# Single fetch gets everything inline - matching sync implementation
368-
full_checkpoint_data = await self._redis.json().get(checkpoint_key)
368+
full_checkpoint_data = await self._redis.json().get(checkpoint_key) # type: ignore[misc]
369369
if not full_checkpoint_data or not isinstance(full_checkpoint_data, dict):
370370
return None
371371

@@ -544,7 +544,7 @@ async def aget_channel_values(
544544
)
545545

546546
# Single JSON.GET operation to retrieve checkpoint with inline channel_values
547-
checkpoint_data = await self._redis.json().get(checkpoint_key, "$.checkpoint")
547+
checkpoint_data = await self._redis.json().get(checkpoint_key, "$.checkpoint") # type: ignore[misc]
548548

549549
if not checkpoint_data:
550550
return {}

langgraph/checkpoint/redis/base.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -558,7 +558,8 @@ def _load_writes_from_redis(self, write_key: str) -> List[Tuple[str, str, Any]]:
558558
return []
559559

560560
# Get the full JSON document
561-
result = self._redis.json().get(write_key)
561+
# Cast needed: redis-py types json().get() as List[JsonType] but returns dict
562+
result = cast(Optional[Dict[str, Any]], self._redis.json().get(write_key))
562563
if not result:
563564
return []
564565

langgraph/store/redis/__init__.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -540,8 +540,9 @@ def _batch_search_ops(
540540
score = (1.0 - float(dist)) if dist is not None else 0.0
541541
if not isinstance(store_doc, dict):
542542
try:
543+
# Cast needed: redis-py types json().get() incorrectly
543544
store_doc = json.loads(
544-
store_doc
545+
cast(str, store_doc)
545546
) # Attempt to parse if it's a JSON string
546547
except (json.JSONDecodeError, TypeError):
547548
logger.error(f"Failed to parse store_doc: {store_doc}")

langgraph/store/redis/aio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ async def _batch_search_ops(
781781
)
782782
result_map[store_key] = doc
783783
# Fetch individually in cluster mode
784-
store_doc_item = await self._redis.json().get(store_key)
784+
store_doc_item = await self._redis.json().get(store_key) # type: ignore[misc]
785785
store_docs.append(store_doc_item)
786786
store_docs_raw = store_docs
787787
else:

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ exclude = '''
104104
disallow_untyped_defs = true
105105
explicit_package_bases = true
106106
warn_no_return = false
107-
warn_unused_ignores = true
107+
warn_unused_ignores = false
108108
warn_redundant_casts = true
109109
allow_redefinition = true
110110
ignore_missing_imports = true

0 commit comments

Comments
 (0)