From 039729a70d1d683b44fba6ec93f76f241f2db7a0 Mon Sep 17 00:00:00 2001 From: Sydney Runkle Date: Tue, 28 Apr 2026 18:02:18 -0400 Subject: [PATCH] refactor(channels): extract _operators_equal helper, deduplicate __eq__ logic MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Both BinaryOperatorAggregate and DeltaChannel had identical inline logic for comparing operators that may be lambdas. Extract _operators_equal into binop.py (alongside _get_overwrite) and use it in both __eq__ methods. Also removes the duplicate _get_overwrite definition from delta.py — it was identical to binop.py's and is now imported from there instead, along with the now-unused OVERWRITE constant and Overwrite imports. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- libs/langgraph/langgraph/channels/binop.py | 18 +++++++++++++----- libs/langgraph/langgraph/channels/delta.py | 18 ++---------------- 2 files changed, 15 insertions(+), 21 deletions(-) diff --git a/libs/langgraph/langgraph/channels/binop.py b/libs/langgraph/langgraph/channels/binop.py index 29fa2a22f..82f7e940e 100644 --- a/libs/langgraph/langgraph/channels/binop.py +++ b/libs/langgraph/langgraph/channels/binop.py @@ -37,6 +37,17 @@ def _get_overwrite(value: Any) -> tuple[bool, Any]: return False, None +def _operators_equal(a: Callable, b: Callable) -> bool: + """Return True if two reducer operators should be considered equal. + + Lambdas all share the name '' so identity comparison is + unreliable; treat any pairing that includes a lambda as equal. + """ + if a.__name__ == "" or b.__name__ == "": + return True + return a is b + + class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]): """Stores the result of applying a binary operator to the current value and each new value. @@ -67,11 +78,8 @@ class BinaryOperatorAggregate(Generic[Value], BaseChannel[Value, Value, Value]): self.value = MISSING def __eq__(self, value: object) -> bool: - return isinstance(value, BinaryOperatorAggregate) and ( - value.operator is self.operator - if value.operator.__name__ != "" - and self.operator.__name__ != "" - else True + return isinstance(value, BinaryOperatorAggregate) and _operators_equal( + self.operator, value.operator ) @property diff --git a/libs/langgraph/langgraph/channels/delta.py b/libs/langgraph/langgraph/channels/delta.py index 7be783013..a061e21a2 100644 --- a/libs/langgraph/langgraph/channels/delta.py +++ b/libs/langgraph/langgraph/channels/delta.py @@ -8,16 +8,15 @@ from langgraph.checkpoint.base import DELTA_SENTINEL, PendingWrite from langgraph.checkpoint.serde.types import _DeltaSnapshot from typing_extensions import Self -from langgraph._internal._constants import OVERWRITE from langgraph._internal._typing import MISSING from langgraph.channels.base import BaseChannel, Value +from langgraph.channels.binop import _get_overwrite, _operators_equal from langgraph.errors import ( EmptyChannelError, ErrorCode, InvalidUpdateError, create_error_message, ) -from langgraph.types import Overwrite __all__ = ("DeltaChannel",) @@ -29,14 +28,6 @@ def _empty(typ: Any) -> Any: return [] -def _get_overwrite(value: Any) -> tuple[bool, Any]: - if isinstance(value, Overwrite): - return True, value.value - if isinstance(value, dict) and set(value.keys()) == {OVERWRITE}: - return True, value[OVERWRITE] - return False, None - - class DeltaChannel(Generic[Value], BaseChannel[Any, Any, Any]): """Fold-reducer channel with configurable snapshot cadence. @@ -74,12 +65,7 @@ class DeltaChannel(Generic[Value], BaseChannel[Any, Any, Any]): return False if self.snapshot_frequency != other.snapshot_frequency: return False - if ( - self.operator.__name__ != "" - and other.operator.__name__ != "" - ): - return self.operator is other.operator - return True + return _operators_equal(self.operator, other.operator) @property def ValueType(self) -> Any: