From 759eba7fd243ceb01bb13cb4e5df4b64bd643868 Mon Sep 17 00:00:00 2001 From: Sydney Runkle Date: Wed, 22 Apr 2026 18:41:06 -0400 Subject: [PATCH] eh --- .../langgraph/checkpoint/base/__init__.py | 23 +++++++++++++++---- .../langgraph/checkpoint/memory/__init__.py | 5 ++-- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/libs/checkpoint/langgraph/checkpoint/base/__init__.py b/libs/checkpoint/langgraph/checkpoint/base/__init__.py index f8fb8bbb7..2ee1452af 100644 --- a/libs/checkpoint/langgraph/checkpoint/base/__init__.py +++ b/libs/checkpoint/langgraph/checkpoint/base/__init__.py @@ -40,6 +40,21 @@ PendingWrite = tuple[str, str, Any] _DELTA_RECONSTRUCTION: threading.local = threading.local() +def _overwrite_types() -> tuple[type, ...]: + """Return `(Overwrite,)` if `langgraph` is installed, else `()`. + + `Overwrite` lives in `langgraph.types`, which this library does not depend + on; importing eagerly would also be circular. An empty tuple makes + `isinstance(x, overwrite_types)` safely return `False` when `langgraph` is + not installed — no `Overwrite` values can exist in that environment. + """ + try: + from langgraph.types import Overwrite # type: ignore[import-untyped] + except ImportError: + return () + return (Overwrite,) + + logger = logging.getLogger(__name__) @@ -487,7 +502,7 @@ class BaseCheckpointSaver(Generic[V]): # it only reads pending_writes). This breaks the recursion safely. if getattr(_DELTA_RECONSTRUCTION, "active", False): return [] - from langgraph.types import Overwrite # type: ignore[import-untyped] + overwrite_types = _overwrite_types() _DELTA_RECONSTRUCTION.active = True try: @@ -504,7 +519,7 @@ class BaseCheckpointSaver(Generic[V]): if ch != channel: continue collected.append(value) - if isinstance(value, Overwrite): + if isinstance(value, overwrite_types): collected.reverse() return collected collected.reverse() @@ -516,7 +531,7 @@ class BaseCheckpointSaver(Generic[V]): self, config: RunnableConfig, channel: str ) -> List[Any]: # noqa: UP006 """Async version of get_channel_writes.""" - from langgraph.types import Overwrite + overwrite_types = _overwrite_types() if getattr(_DELTA_RECONSTRUCTION, "active", False): return [] @@ -533,7 +548,7 @@ class BaseCheckpointSaver(Generic[V]): if ch != channel: continue collected.append(value) - if isinstance(value, Overwrite): + if isinstance(value, overwrite_types): collected.reverse() return collected collected.reverse() diff --git a/libs/checkpoint/langgraph/checkpoint/memory/__init__.py b/libs/checkpoint/langgraph/checkpoint/memory/__init__.py index 9947be125..d9558c8f6 100644 --- a/libs/checkpoint/langgraph/checkpoint/memory/__init__.py +++ b/libs/checkpoint/langgraph/checkpoint/memory/__init__.py @@ -23,6 +23,7 @@ from langgraph.checkpoint.base import ( CheckpointTuple, DeltaChannelWrites, SerializerProtocol, + _overwrite_types, get_checkpoint_id, get_checkpoint_metadata, ) @@ -168,7 +169,7 @@ class InMemorySaver( chain.append(current) _, _, parent = entry current = parent - from langgraph.types import Overwrite # type: ignore[import-untyped] + overwrite_types = _overwrite_types() # Scan writes newest→oldest. Stop at the first `Overwrite` — it # dominates all older history. Either from `snapshot_every` or from @@ -185,7 +186,7 @@ class InMemorySaver( continue val = self.serde.loads_typed(serialized) collected.append(val) - if isinstance(val, Overwrite): + if isinstance(val, overwrite_types): collected.reverse() return collected collected.reverse()