From 72fb0090bd1bc7ac0e0e492827cd05814b3d2408 Mon Sep 17 00:00:00 2001 From: Mason Daugherty Date: Tue, 18 Aug 2026 16:16:21 -0400 Subject: [PATCH] test(core): avoid version-dependent runnable snapshots (#39705) Runnable snapshots currently embed the exact `langchain-core` version, forcing unrelated snapshot rewrites during every release. Normalize only the current `VERSION` to a stable placeholder before comparison, so missing or stale version metadata still fails. Made by [Open SWE](https://openswe.vercel.app/agents/bfd72574-359e-544e-dbf5-78f8bae3636a) Co-authored-by: open-swe[bot] --- .../__snapshots__/test_fallbacks.ambr | 14 +++--- .../__snapshots__/test_runnable.ambr | 48 +++++++++---------- .../unit_tests/runnables/test_fallbacks.py | 10 +++- .../unit_tests/runnables/test_runnable.py | 45 +++++++++-------- 4 files changed, 66 insertions(+), 51 deletions(-) diff --git a/libs/core/tests/unit_tests/runnables/__snapshots__/test_fallbacks.ambr b/libs/core/tests/unit_tests/runnables/__snapshots__/test_fallbacks.ambr index 3ae4c117b0..3f77cae6ca 100644 --- a/libs/core/tests/unit_tests/runnables/__snapshots__/test_fallbacks.ambr +++ b/libs/core/tests/unit_tests/runnables/__snapshots__/test_fallbacks.ambr @@ -84,7 +84,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo'], i=1)", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo'], i=1)", "name": "FakeListLLM" } }, @@ -128,7 +128,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['bar'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['bar'])", "name": "FakeListLLM" } }, @@ -268,7 +268,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo'], i=1)", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo'], i=1)", "name": "FakeListLLM" }, "fallbacks": [ @@ -281,7 +281,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['bar'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['bar'])", "name": "FakeListLLM" } ], @@ -322,7 +322,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo'], i=1)", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo'], i=1)", "name": "FakeListLLM" }, "fallbacks": [ @@ -335,7 +335,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['baz'], i=1)", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['baz'], i=1)", "name": "FakeListLLM" }, { @@ -347,7 +347,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['bar'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['bar'])", "name": "FakeListLLM" } ], diff --git a/libs/core/tests/unit_tests/runnables/__snapshots__/test_runnable.ambr b/libs/core/tests/unit_tests/runnables/__snapshots__/test_runnable.ambr index 6d1996f451..c25b22bfb6 100644 --- a/libs/core/tests/unit_tests/runnables/__snapshots__/test_runnable.ambr +++ b/libs/core/tests/unit_tests/runnables/__snapshots__/test_runnable.ambr @@ -97,7 +97,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo, bar'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo, bar'])", "name": "FakeListChatModel" } ], @@ -227,7 +227,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['baz, qux'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['baz, qux'])", "name": "FakeListChatModel" } ], @@ -346,7 +346,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo, bar'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo, bar'])", "name": "FakeListChatModel" }, { @@ -457,7 +457,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['baz, qux'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['baz, qux'])", "name": "FakeListChatModel" } ], @@ -848,7 +848,7 @@ "fake", "FakeStreamingListLLM" ], - "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['first item, second item, third item'])", + "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['first item, second item, third item'])", "name": "FakeStreamingListLLM" }, { @@ -884,7 +884,7 @@ "fake", "FakeStreamingListLLM" ], - "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['this', 'is', 'a', 'test'])", + "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['this', 'is', 'a', 'test'])", "name": "FakeStreamingListLLM" } }, @@ -1009,7 +1009,7 @@ # name: test_prompt_with_chat_model ''' ChatPromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a nice assistant.'), additional_kwargs={}), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, template='{question}'), additional_kwargs={})]) - | FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo']) + | FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo']) ''' # --- # name: test_prompt_with_chat_model.1 @@ -1109,7 +1109,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo'])", "name": "FakeListChatModel" } }, @@ -1220,7 +1220,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo, bar'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo, bar'])", "name": "FakeListChatModel" } ], @@ -1249,7 +1249,7 @@ # name: test_prompt_with_chat_model_async ''' ChatPromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a nice assistant.'), additional_kwargs={}), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, template='{question}'), additional_kwargs={})]) - | FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo']) + | FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo']) ''' # --- # name: test_prompt_with_chat_model_async.1 @@ -1349,7 +1349,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo'])", "name": "FakeListChatModel" } }, @@ -1459,7 +1459,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo', 'bar'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo', 'bar'])", "name": "FakeListLLM" } }, @@ -1576,7 +1576,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo', 'bar'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo', 'bar'])", "name": "FakeListLLM" } ], @@ -1699,7 +1699,7 @@ "fake", "FakeStreamingListLLM" ], - "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['bear, dog, cat', 'tomato, lettuce, onion'])", + "repr": "FakeStreamingListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['bear, dog, cat', 'tomato, lettuce, onion'])", "name": "FakeStreamingListLLM" } ], @@ -1867,7 +1867,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['4'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['4'])", "name": "FakeListLLM" } }, @@ -1940,7 +1940,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['2'])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=['2'])", "name": "FakeListLLM" } }, @@ -13407,7 +13407,7 @@ just_to_test_lambda: RunnableLambda(...) } | ChatPromptTemplate(input_variables=['documents', 'question'], input_types={}, partial_variables={}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a nice assistant.'), additional_kwargs={}), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['documents', 'question'], input_types={}, partial_variables={}, template='Context:\n{documents}\n\nQuestion:\n{question}'), additional_kwargs={})]) - | FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo, bar']) + | FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo, bar']) | CommaSeparatedListOutputParser() ''' # --- @@ -13610,7 +13610,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=['foo, bar'])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=['foo, bar'])", "name": "FakeListChatModel" } ], @@ -13636,8 +13636,8 @@ ChatPromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, messages=[SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], input_types={}, partial_variables={}, template='You are a nice assistant.'), additional_kwargs={}), HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=['question'], input_types={}, partial_variables={}, template='{question}'), additional_kwargs={})]) | RunnableLambda(...) | { - chat: FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=["i'm a chatbot"]), - llm: FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=["i'm a textbot"]) + chat: FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=["i'm a chatbot"]), + llm: FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=["i'm a textbot"]) } ''' # --- @@ -13762,7 +13762,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=[\"i'm a chatbot\"])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=[\"i'm a chatbot\"])", "name": "FakeListChatModel" }, "llm": { @@ -13774,7 +13774,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=[\"i'm a textbot\"])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=[\"i'm a textbot\"])", "name": "FakeListLLM" } } @@ -13917,7 +13917,7 @@ "fake_chat_models", "FakeListChatModel" ], - "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=[\"i'm a chatbot\"])", + "repr": "FakeListChatModel(metadata={'lc_versions': {'langchain-core': ''}}, responses=[\"i'm a chatbot\"])", "name": "FakeListChatModel" }, "kwargs": { @@ -13938,7 +13938,7 @@ "fake", "FakeListLLM" ], - "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': '1.5.6'}}, responses=[\"i'm a textbot\"])", + "repr": "FakeListLLM(metadata={'lc_versions': {'langchain-core': ''}}, responses=[\"i'm a textbot\"])", "name": "FakeListLLM" }, "passthrough": { diff --git a/libs/core/tests/unit_tests/runnables/test_fallbacks.py b/libs/core/tests/unit_tests/runnables/test_fallbacks.py index 11e02f3939..8b251d6745 100644 --- a/libs/core/tests/unit_tests/runnables/test_fallbacks.py +++ b/libs/core/tests/unit_tests/runnables/test_fallbacks.py @@ -28,6 +28,14 @@ from langchain_core.runnables import ( RunnableWithFallbacks, ) from langchain_core.tools import BaseTool +from langchain_core.version import VERSION + + +def _normalize_lc_version(value: str) -> str: + return value.replace( + f"'langchain-core': '{VERSION}'", + "'langchain-core': ''", + ) @pytest.fixture @@ -87,7 +95,7 @@ def test_fallbacks( assert runnable.invoke("hello") == "bar" assert runnable.batch(["hi", "hey", "bye"]) == ["bar"] * 3 assert list(runnable.stream("hello")) == ["bar"] - assert dumps(runnable, pretty=True) == snapshot + assert _normalize_lc_version(dumps(runnable, pretty=True)) == snapshot @pytest.mark.parametrize( diff --git a/libs/core/tests/unit_tests/runnables/test_runnable.py b/libs/core/tests/unit_tests/runnables/test_runnable.py index 24b986a2eb..2a62e88d48 100644 --- a/libs/core/tests/unit_tests/runnables/test_runnable.py +++ b/libs/core/tests/unit_tests/runnables/test_runnable.py @@ -117,6 +117,13 @@ PYDANTIC_VERSION_AT_LEAST_29 = version.parse("2.9") <= PYDANTIC_VERSION PYDANTIC_VERSION_AT_LEAST_210 = version.parse("2.10") <= PYDANTIC_VERSION +def _normalize_lc_version(value: str) -> str: + return value.replace( + f"'langchain-core': '{VERSION}'", + "'langchain-core': ''", + ) + + class FakeTracer(BaseTracer): """Fake tracer that records LangChain execution. @@ -1799,12 +1806,12 @@ def test_prompt_with_chat_model( chain = prompt | chat - assert repr(chain) == snapshot + assert _normalize_lc_version(repr(chain)) == snapshot assert isinstance(chain, RunnableSequence) assert chain.first == prompt assert chain.middle == [] assert chain.last == chat - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "invoke") @@ -1905,12 +1912,12 @@ async def test_prompt_with_chat_model_async( chain = prompt | chat - assert repr(chain) == snapshot + assert _normalize_lc_version(repr(chain)) == snapshot assert isinstance(chain, RunnableSequence) assert chain.first == prompt assert chain.middle == [] assert chain.last == chat - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "ainvoke") @@ -2023,7 +2030,7 @@ async def test_prompt_with_llm( assert chain.first == prompt assert chain.middle == [] assert chain.last == llm - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "ainvoke") @@ -2224,7 +2231,7 @@ async def test_prompt_with_llm_parser( assert chain.first == prompt assert chain.middle == [llm] assert chain.last == parser - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "ainvoke") @@ -2617,7 +2624,7 @@ async def test_prompt_with_llm_and_async_lambda( assert chain.first == prompt assert chain.middle == [llm] assert chain.last == RunnableLambda(func=passthrough) - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "ainvoke") @@ -2658,7 +2665,7 @@ def test_prompt_with_chat_model_and_parser( assert chain.first == prompt assert chain.middle == [chat] assert chain.last == parser - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "invoke") @@ -2698,7 +2705,7 @@ def test_combining_sequences( assert chain.first == prompt assert chain.middle == [chat] assert chain.last == parser - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot prompt2 = ( SystemMessagePromptTemplate.from_template("You are a nicer assistant.") @@ -2716,7 +2723,7 @@ def test_combining_sequences( assert chain2.first == input_formatter assert chain2.middle == [prompt2, chat2] assert chain2.last == parser2 - assert dumps(chain2, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain2, pretty=True)) == snapshot combined_chain = chain | chain2 @@ -2730,7 +2737,7 @@ def test_combining_sequences( chat2, ] assert combined_chain.last == parser2 - assert dumps(combined_chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(combined_chain, pretty=True)) == snapshot # Test invoke tracer = FakeTracer() @@ -2773,12 +2780,12 @@ Question: | parser ) - assert repr(chain) == snapshot + assert _normalize_lc_version(repr(chain)) == snapshot assert isinstance(chain, RunnableSequence) assert isinstance(chain.first, RunnableParallel) assert chain.middle == [prompt, chat] assert chain.last == parser - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "invoke") @@ -2844,12 +2851,12 @@ def test_seq_prompt_dict(mocker: MockerFixture, snapshot: SnapshotAssertion) -> } ) - assert repr(chain) == snapshot + assert _normalize_lc_version(repr(chain)) == snapshot assert isinstance(chain, RunnableSequence) assert chain.first == prompt assert chain.middle == [RunnableLambda(passthrough)] assert isinstance(chain.last, RunnableParallel) - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "invoke") @@ -2896,7 +2903,7 @@ def test_router_runnable(mocker: MockerFixture, snapshot: SnapshotAssertion) -> "key": lambda x: x["key"], "input": {"question": lambda x: x["question"]}, } | router - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot result = chain.invoke({"key": "math", "question": "2 + 2"}) assert result == "4" @@ -2977,7 +2984,7 @@ def test_higher_order_lambda_runnable( raise ValueError(msg) chain = input_map | router - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot result = chain.invoke({"key": "math", "question": "2 + 2"}) assert result == "4" @@ -3107,7 +3114,7 @@ def test_seq_prompt_map(mocker: MockerFixture, snapshot: SnapshotAssertion) -> N assert isinstance(chain.last, RunnableParallel) if PYDANTIC_VERSION_AT_LEAST_210: - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot # Test invoke prompt_spy = mocker.spy(prompt.__class__, "invoke") @@ -3914,7 +3921,7 @@ def test_each(snapshot: SnapshotAssertion) -> None: chain = prompt | first_llm | parser | second_llm.map() - assert dumps(chain, pretty=True) == snapshot + assert _normalize_lc_version(dumps(chain, pretty=True)) == snapshot output = chain.invoke({"question": "What up"}) assert output == ["this", "is", "a"]