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
240 lines
7.8 KiB
Python
240 lines
7.8 KiB
Python
import os
|
|
from contextlib import asynccontextmanager, contextmanager
|
|
from uuid import uuid4
|
|
|
|
import pytest
|
|
from langgraph.checkpoint.postgres import PostgresSaver
|
|
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
|
from langgraph.checkpoint.serde.encrypted import EncryptedSerializer
|
|
from langgraph.checkpoint.serde.jsonplus import JsonPlusSerializer
|
|
from langgraph.checkpoint.sqlite import SqliteSaver
|
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
|
from psycopg import AsyncConnection, Connection
|
|
from psycopg_pool import AsyncConnectionPool, ConnectionPool
|
|
|
|
pytest.register_assert_rewrite("tests.memory_assert")
|
|
|
|
from tests.memory_assert import ( # noqa: E402
|
|
MemorySaverAssertImmutable,
|
|
MemorySaverNeedsPendingSendsMigration,
|
|
)
|
|
|
|
DEFAULT_POSTGRES_URI = "postgres://postgres:postgres@localhost:5442/"
|
|
STRICT_MSGPACK = os.getenv("LANGGRAPH_STRICT_MSGPACK", "false").lower() in (
|
|
"1",
|
|
"true",
|
|
"yes",
|
|
)
|
|
|
|
|
|
def _strict_msgpack_serde() -> JsonPlusSerializer:
|
|
return JsonPlusSerializer(allowed_msgpack_modules=None)
|
|
|
|
|
|
def _apply_strict_msgpack(checkpointer) -> None:
|
|
if not STRICT_MSGPACK:
|
|
return
|
|
serde = _strict_msgpack_serde()
|
|
if hasattr(checkpointer, "serde"):
|
|
checkpointer.serde = serde
|
|
if hasattr(checkpointer, "saver") and hasattr(checkpointer.saver, "serde"):
|
|
checkpointer.saver.serde = serde
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_memory():
|
|
if STRICT_MSGPACK:
|
|
yield MemorySaverAssertImmutable(serde=_strict_msgpack_serde())
|
|
else:
|
|
yield MemorySaverAssertImmutable()
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_memory_migrate_sends():
|
|
checkpointer = MemorySaverNeedsPendingSendsMigration()
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_sqlite():
|
|
with SqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_sqlite_aes():
|
|
with SqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
if STRICT_MSGPACK:
|
|
checkpointer.serde = EncryptedSerializer.from_pycryptodome_aes(
|
|
serde=_strict_msgpack_serde(), key=b"1234567890123456"
|
|
)
|
|
else:
|
|
checkpointer.serde = EncryptedSerializer.from_pycryptodome_aes(
|
|
key=b"1234567890123456"
|
|
)
|
|
yield checkpointer
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_postgres():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
with PostgresSaver.from_conn_string(
|
|
DEFAULT_POSTGRES_URI + database
|
|
) as checkpointer:
|
|
checkpointer.setup()
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_postgres_pipe():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
with PostgresSaver.from_conn_string(
|
|
DEFAULT_POSTGRES_URI + database
|
|
) as checkpointer:
|
|
checkpointer.setup()
|
|
# setup can't run inside pipeline because of implicit transaction
|
|
with checkpointer.conn.pipeline() as pipe:
|
|
checkpointer.pipe = pipe
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
@contextmanager
|
|
def _checkpointer_postgres_pool():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
with ConnectionPool(
|
|
DEFAULT_POSTGRES_URI + database, max_size=10, kwargs={"autocommit": True}
|
|
) as pool:
|
|
checkpointer = PostgresSaver(pool)
|
|
checkpointer.setup()
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
with Connection.connect(DEFAULT_POSTGRES_URI, autocommit=True) as conn:
|
|
conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def _checkpointer_sqlite_aio():
|
|
async with AsyncSqliteSaver.from_conn_string(":memory:") as checkpointer:
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
|
|
|
|
@asynccontextmanager
|
|
async def _checkpointer_postgres_aio():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
async with AsyncPostgresSaver.from_conn_string(
|
|
DEFAULT_POSTGRES_URI + database
|
|
) as checkpointer:
|
|
await checkpointer.setup()
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def _checkpointer_postgres_aio_pipe():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
async with AsyncPostgresSaver.from_conn_string(
|
|
DEFAULT_POSTGRES_URI + database
|
|
) as checkpointer:
|
|
await checkpointer.setup()
|
|
# setup can't run inside pipeline because of implicit transaction
|
|
async with checkpointer.conn.pipeline() as pipe:
|
|
checkpointer.pipe = pipe
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
@asynccontextmanager
|
|
async def _checkpointer_postgres_aio_pool():
|
|
database = f"test_{uuid4().hex[:16]}"
|
|
# create unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"CREATE DATABASE {database}")
|
|
try:
|
|
# yield checkpointer
|
|
async with AsyncConnectionPool(
|
|
DEFAULT_POSTGRES_URI + database, max_size=10, kwargs={"autocommit": True}
|
|
) as pool:
|
|
checkpointer = AsyncPostgresSaver(pool)
|
|
await checkpointer.setup()
|
|
_apply_strict_msgpack(checkpointer)
|
|
yield checkpointer
|
|
finally:
|
|
# drop unique db
|
|
async with await AsyncConnection.connect(
|
|
DEFAULT_POSTGRES_URI, autocommit=True
|
|
) as conn:
|
|
await conn.execute(f"DROP DATABASE {database}")
|
|
|
|
|
|
__all__ = [
|
|
"_checkpointer_memory",
|
|
"_checkpointer_memory_migrate_sends",
|
|
"_checkpointer_sqlite",
|
|
"_checkpointer_sqlite_aes",
|
|
"_checkpointer_postgres",
|
|
"_checkpointer_postgres_pipe",
|
|
"_checkpointer_postgres_pool",
|
|
"_checkpointer_sqlite_aio",
|
|
"_checkpointer_postgres_aio",
|
|
"_checkpointer_postgres_aio_pipe",
|
|
"_checkpointer_postgres_aio_pool",
|
|
]
|