Files
wehub-resource-sync a7d6d88f6f
CI / changes (push) Has been cancelled
CI / cd libs/checkpoint (push) Has been cancelled
CI / cd libs/checkpoint-conformance (push) Has been cancelled
CI / cd libs/checkpoint-postgres (push) Has been cancelled
CI / cd libs/checkpoint-sqlite (push) Has been cancelled
CI / cd libs/cli (push) Has been cancelled
CI / cd libs/prebuilt (push) Has been cancelled
CI / cd libs/sdk-py (push) Has been cancelled
CI / cd libs/langgraph (push) Has been cancelled
CI / Check SDK methods matching (push) Has been cancelled
CI / Check CLI schema hasn't changed #3.13 (push) Has been cancelled
CI / CLI integration test (push) Has been cancelled
CI / sdk-py integration test (push) Has been cancelled
CI / CI Success (push) Has been cancelled
baseline / benchmark (push) Has been cancelled
Deploy Redirects to GitHub Pages / deploy (push) Has been cancelled
chore: import upstream snapshot with attribution
2026-07-13 12:37:18 +08:00

101 lines
2.9 KiB
Python

"""Checkpointer test registration and factory management."""
from __future__ import annotations
from collections.abc import AsyncGenerator, Callable
from contextlib import asynccontextmanager
from dataclasses import dataclass, field
from typing import Any
from langgraph.checkpoint.base import BaseCheckpointSaver
# Type for the lifespan async context manager factory.
LifespanFactory = Callable[[], AsyncGenerator[None, None]]
# Module-level registry of decorated checkpointer factories.
_REGISTRY: dict[str, RegisteredCheckpointer] = {}
async def _noop_lifespan() -> AsyncGenerator[None, None]:
yield
@dataclass
class RegisteredCheckpointer:
"""A registered checkpointer test factory."""
name: str
factory: Callable[[], AsyncGenerator[BaseCheckpointSaver, None]]
skip_capabilities: set[str] = field(default_factory=set)
lifespan: LifespanFactory = _noop_lifespan
@asynccontextmanager
async def create(self) -> AsyncGenerator[BaseCheckpointSaver, None]:
"""Create a fresh checkpointer instance via the async generator."""
gen = self.factory()
try:
saver = await gen.__anext__()
yield saver
finally:
try:
await gen.__anext__()
except StopAsyncIteration:
pass
@asynccontextmanager
async def enter_lifespan(self) -> AsyncGenerator[None, None]:
"""Enter the lifespan context (once per validation run)."""
gen = self.lifespan()
try:
await gen.__anext__()
yield
finally:
try:
await gen.__anext__()
except StopAsyncIteration:
pass
def checkpointer_test(
name: str,
*,
skip_capabilities: set[str] | None = None,
lifespan: LifespanFactory | None = None,
) -> Callable[[Any], RegisteredCheckpointer]:
"""Register an async generator as a checkpointer test factory.
The factory is called once per capability suite to create a fresh
checkpointer. The optional `lifespan` is an async generator that
runs once for the entire validation run (e.g. to create/destroy a
database).
Example::
@checkpointer_test(name="InMemorySaver")
async def memory_checkpointer():
yield InMemorySaver()
With lifespan::
async def pg_lifespan():
await create_database()
yield
await drop_database()
@checkpointer_test(name="PostgresSaver", lifespan=pg_lifespan)
async def pg_checkpointer():
yield PostgresSaver(conn_string="...")
"""
def decorator(fn: Any) -> RegisteredCheckpointer:
registered = RegisteredCheckpointer(
name=name,
factory=fn,
skip_capabilities=skip_capabilities or set(),
lifespan=lifespan or _noop_lifespan,
)
_REGISTRY[name] = registered
return registered
return decorator