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

380 lines
13 KiB
Python

from __future__ import annotations
import warnings
from typing import Any, Optional
import pytest
from langchain_core.runnables import RunnableConfig
from pytest_mock import MockerFixture
from typing_extensions import NotRequired, TypedDict
from langgraph.channels.last_value import LastValue
from langgraph.errors import NodeInterrupt
from langgraph.func import entrypoint, task
from langgraph.graph import StateGraph
from langgraph.graph.message import MessageGraph
from langgraph.pregel import NodeBuilder, Pregel
from langgraph.types import GraphOutput, Interrupt, RetryPolicy
from langgraph.warnings import (
LangGraphDeprecatedSinceV05,
LangGraphDeprecatedSinceV10,
LangGraphDeprecatedSinceV11,
)
class PlainState(TypedDict): ...
def test_add_node_retry_arg() -> None:
builder = StateGraph(PlainState)
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`retry` is deprecated and will be removed. Please use `retry_policy` instead.",
):
builder.add_node("test_node", lambda state: state, retry=RetryPolicy()) # type: ignore[arg-type]
def test_task_retry_arg() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`retry` is deprecated and will be removed. Please use `retry_policy` instead.",
):
@task(retry=RetryPolicy()) # type: ignore[arg-type]
def my_task(state: PlainState) -> PlainState:
return state
def test_entrypoint_retry_arg() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`retry` is deprecated and will be removed. Please use `retry_policy` instead.",
):
@entrypoint(retry=RetryPolicy()) # type: ignore[arg-type]
def my_entrypoint(state: PlainState) -> PlainState:
return state
def test_state_graph_input_schema() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`input` is deprecated and will be removed. Please use `input_schema` instead.",
):
StateGraph(PlainState, input=PlainState) # type: ignore[arg-type]
def test_state_graph_output_schema() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`output` is deprecated and will be removed. Please use `output_schema` instead.",
):
StateGraph(PlainState, output=PlainState) # type: ignore[arg-type]
def test_add_node_input_schema() -> None:
builder = StateGraph(PlainState)
with pytest.warns(
LangGraphDeprecatedSinceV05,
match="`input` is deprecated and will be removed. Please use `input_schema` instead.",
):
builder.add_node("test_node", lambda state: state, input=PlainState) # type: ignore[arg-type]
def test_constants_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="Importing Send from langgraph.constants is deprecated. Please use 'from langgraph.types import Send' instead.",
):
from langgraph.constants import Send # noqa: F401
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="Importing Interrupt from langgraph.constants is deprecated. Please use 'from langgraph.types import Interrupt' instead.",
):
from langgraph.constants import Interrupt # noqa: F401
def test_pregel_types_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="Importing from langgraph.pregel.types is deprecated. Please use 'from langgraph.types import ...' instead.",
):
from langgraph.pregel.types import StateSnapshot # noqa: F401
def test_config_schema_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
):
builder = StateGraph(PlainState, config_schema=PlainState)
assert builder.context_schema == PlainState
builder.add_node("test_node", lambda state: state)
builder.set_entry_point("test_node")
graph = builder.compile()
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated. Use `get_context_jsonschema` for the relevant schema instead.",
):
assert graph.config_schema() is not None
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`get_config_jsonschema` is deprecated. Use `get_context_jsonschema` instead.",
):
graph.get_config_jsonschema()
def test_config_schema_deprecation_on_entrypoint() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated and will be removed. Please use `context_schema` instead.",
):
@entrypoint(config_schema=PlainState) # type: ignore[arg-type]
def my_entrypoint(state: PlainState) -> PlainState:
return state
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_schema` is deprecated. Use `get_context_jsonschema` for the relevant schema instead.",
):
assert my_entrypoint.context_schema == PlainState
assert my_entrypoint.config_schema() is not None
@pytest.mark.filterwarnings("ignore:`config_type` is deprecated")
def test_config_type_deprecation_pregel(mocker: MockerFixture) -> None:
add_one = mocker.Mock(side_effect=lambda x: x + 1)
chain = NodeBuilder().subscribe_only("input").do(add_one).write_to("output")
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`config_type` is deprecated and will be removed. Please use `context_schema` instead.",
):
instance = Pregel(
nodes={
"one": chain,
},
channels={
"input": LastValue(int),
"output": LastValue(int),
},
input_channels="input",
output_channels="output",
config_type=PlainState,
)
assert instance.context_schema == PlainState
def test_interrupt_attributes_deprecation() -> None:
interrupt = Interrupt(value="question", id="abc")
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`interrupt_id` is deprecated. Use `id` instead.",
):
interrupt.interrupt_id
def test_node_interrupt_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="NodeInterrupt is deprecated. Please use `langgraph.types.interrupt` instead.",
):
NodeInterrupt(value="test")
def test_deprecated_import() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="Importing PREVIOUS from langgraph.constants is deprecated. This constant is now private and should not be used directly.",
):
from langgraph.constants import PREVIOUS # noqa: F401
@pytest.mark.filterwarnings(
"ignore:`durability` has no effect when no checkpointer is present"
)
@pytest.mark.filterwarnings("ignore:Accessing GraphOutput via")
def test_checkpoint_during_deprecation_state_graph() -> None:
class CheckDurability(TypedDict):
durability: NotRequired[str]
def plain_node(state: CheckDurability, config: RunnableConfig) -> CheckDurability:
return {"durability": config["configurable"]["__pregel_durability"]}
builder = StateGraph(CheckDurability)
builder.add_node("plain_node", plain_node)
builder.set_entry_point("plain_node")
graph = builder.compile()
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`checkpoint_during` is deprecated and will be removed. Please use `durability` instead.",
):
result = graph.invoke({}, checkpoint_during=True)
assert result["durability"] == "async"
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`checkpoint_during` is deprecated and will be removed. Please use `durability` instead.",
):
result = graph.invoke({}, checkpoint_during=False)
assert result["durability"] == "exit"
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`checkpoint_during` is deprecated and will be removed. Please use `durability` instead.",
):
for chunk in graph.stream({}, checkpoint_during=True): # type: ignore[arg-type]
assert chunk["plain_node"]["durability"] == "async"
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="`checkpoint_during` is deprecated and will be removed. Please use `durability` instead.",
):
for chunk in graph.stream({}, checkpoint_during=False): # type: ignore[arg-type]
assert chunk["plain_node"]["durability"] == "exit"
def test_config_parameter_incorrect_typing() -> None:
"""Test that a warning is raised when config parameter is typed incorrectly."""
builder = StateGraph(PlainState)
# Test sync function with config: dict
with pytest.warns(
UserWarning,
match="The 'config' parameter should be typed as 'RunnableConfig' or 'RunnableConfig | None', not '.*dict.*'. ",
):
def sync_node_with_dict_config(state: PlainState, config: dict) -> PlainState:
return state
builder.add_node(sync_node_with_dict_config)
# Test async function with config: dict
with pytest.warns(
UserWarning,
match="The 'config' parameter should be typed as 'RunnableConfig' or 'RunnableConfig | None', not '.*dict.*'. ",
):
async def async_node_with_dict_config(
state: PlainState, config: dict
) -> PlainState:
return state
builder.add_node(async_node_with_dict_config)
# Test with other incorrect types
with pytest.warns(
UserWarning,
match="The 'config' parameter should be typed as 'RunnableConfig' or 'RunnableConfig | None', not '.*Any.*'. ",
):
def sync_node_with_any_config(state: PlainState, config: Any) -> PlainState:
return state
builder.add_node(sync_node_with_any_config)
with pytest.warns(
UserWarning,
match="The 'config' parameter should be typed as 'RunnableConfig' or 'RunnableConfig | None', not '.*Any.*'. ",
):
async def async_node_with_any_config(
state: PlainState, config: Any
) -> PlainState:
return state
builder.add_node(async_node_with_any_config)
with warnings.catch_warnings(record=True) as w:
def node_with_correct_config(
state: PlainState, config: RunnableConfig
) -> PlainState:
return state
builder.add_node(node_with_correct_config)
def node_with_optional_config(
state: PlainState,
config: Optional[RunnableConfig], # noqa: UP045
) -> PlainState:
return state
builder.add_node(node_with_optional_config)
def node_with_untyped_config(state: PlainState, config) -> PlainState:
return state
builder.add_node(node_with_untyped_config)
async def async_node_with_correct_config(
state: PlainState, config: RunnableConfig
) -> PlainState:
return state
builder.add_node(async_node_with_correct_config)
async def async_node_with_optional_config(
state: PlainState,
config: Optional[RunnableConfig], # noqa: UP045
) -> PlainState:
return state
builder.add_node(async_node_with_optional_config)
async def async_node_with_untyped_config(
state: PlainState, config
) -> PlainState:
return state
builder.add_node(async_node_with_untyped_config)
assert len(w) == 0
def test_message_graph_deprecation() -> None:
with pytest.warns(
LangGraphDeprecatedSinceV10,
match="MessageGraph is deprecated in LangGraph v1.0.0, to be removed in v2.0.0. Please use StateGraph with a `messages` key instead.",
):
MessageGraph()
def test_graph_output_getitem_deprecation() -> None:
output = GraphOutput(value={"foo": "bar"})
with pytest.warns(
LangGraphDeprecatedSinceV11,
match=r"Accessing GraphOutput via `result\[key\]` is deprecated",
):
assert output["foo"] == "bar"
def test_graph_output_contains_deprecation() -> None:
output = GraphOutput(value={"foo": "bar"})
with pytest.warns(
LangGraphDeprecatedSinceV11,
match=r"Accessing GraphOutput via `key in result` is deprecated",
):
assert "foo" in output
def test_graph_output_getitem_interrupt_deprecation() -> None:
interrupts = (Interrupt(value="q", id="abc"),)
output = GraphOutput(value={"foo": "bar"}, interrupts=interrupts)
with pytest.warns(
LangGraphDeprecatedSinceV11,
match=r"Accessing GraphOutput via `result\[key\]` is deprecated",
):
assert output["__interrupt__"] == interrupts