Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-langgraph for openSUSE:Factory checked in at 2026-10-26 10:03:07 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-langgraph (Old) and /work/SRC/openSUSE:Factory/.python-langgraph.new.2252680 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-langgraph" Mon Oct 26 10:03:07 2026 rev:12 rq:1392568 version:1.2.17 Changes: -------- --- /work/SRC/openSUSE:Factory/python-langgraph/python-langgraph.changes 2026-10-17 21:27:00.553902447 +0200 +++ /work/SRC/openSUSE:Factory/.python-langgraph.new.2252680/python-langgraph.changes 2026-10-26 10:04:32.855150510 +0100 @@ -1,0 +2,9 @@ +Sun Oct 25 06:00:00 UTC 2026 - Martin Pluskal <[email protected]> + +- Update to 1.2.17: + * Apply an explicit recursion_limit equal to the default + * Keep the caller's namespace in RemoteGraph.stream + with subgraphs + * Drop precautionary third-party upper bounds + +------------------------------------------------------------------- Old: ---- langgraph-1.2.16.tar.gz New: ---- langgraph-1.2.17.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-langgraph.spec ++++++ --- /var/tmp/diff_new_pack.6ege1h/_old 2026-10-26 10:04:33.912194822 +0100 +++ /var/tmp/diff_new_pack.6ege1h/_new 2026-10-26 10:04:33.915194948 +0100 @@ -17,7 +17,7 @@ Name: python-langgraph -Version: 1.2.16 +Version: 1.2.17 Release: 0 Summary: Library for building stateful, multi-actor applications with LLMs License: MIT ++++++ langgraph-1.2.16.tar.gz -> langgraph-1.2.17.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/Makefile new/langgraph-1.2.17/Makefile --- old/langgraph-1.2.16/Makefile 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/Makefile 2020-02-02 01:00:00.000000000 +0100 @@ -43,14 +43,31 @@ stop-services: docker compose -f tests/compose-postgres.yml -f tests/compose-redis.yml down -v +DEV_SERVER_PYTHON ?= 3.12 +DEV_SERVER_ENV = $(CURDIR)/.venvs/dev-server + start-dev-server: - LOG_LEVEL=warning uv run langgraph dev --config tests/example_app/langgraph.json --no-browser & echo "$$!" > .devserver.pid - @echo "Dev server started." + uv sync --frozen --group test --no-dev + UV_PROJECT_ENVIRONMENT=$(DEV_SERVER_ENV) uv sync --frozen --group test --no-dev --python $(DEV_SERVER_PYTHON) + @LOG_LEVEL=warning UV_PROJECT_ENVIRONMENT=$(DEV_SERVER_ENV) uv run --no-sync --python $(DEV_SERVER_PYTHON) langgraph dev --config tests/example_app/langgraph.json --no-browser --no-reload & \ + PID=$$!; echo "$$PID" > .devserver.pid; \ + for ATTEMPT in $$(seq 1 60); do \ + if ! kill -0 $$PID 2>/dev/null; then break; fi; \ + if curl --fail --silent --max-time 1 http://localhost:2024/ok >/dev/null; then \ + echo "Dev server ready."; exit 0; \ + fi; \ + sleep 1; \ + done; \ + echo "Dev server failed to become ready." >&2; \ + kill $$PID 2>/dev/null || true; \ + wait $$PID 2>/dev/null || true; \ + rm -f .devserver.pid; exit 1 stop-dev-server: @if [ -f .devserver.pid ]; then \ - kill `cat .devserver.pid` && rm .devserver.pid; \ - echo "Dev server stopped."; \ + kill $$(cat .devserver.pid) 2>/dev/null || true; \ + rm -f .devserver.pid; \ + echo "Dev server stopped."; \ else \ echo "No dev server PID file found."; \ fi @@ -60,13 +77,12 @@ test: if [ "$(NO_DOCKER)" = "false" ]; then \ - make start-services &&\ - make start-dev-server &&\ - uv run pytest $(TEST); \ - EXIT_CODE=$$?; \ - make stop-services; \ - make stop-dev-server; \ - exit $$EXIT_CODE; \ + trap '$(MAKE) stop-dev-server; $(MAKE) stop-services' EXIT; \ + trap 'exit 130' INT; trap 'exit 143' TERM; \ + $(MAKE) start-services &&\ + $(MAKE) start-dev-server &&\ + uv run --no-sync pytest $(TEST); \ + exit $$?; \ else \ NO_DOCKER=true uv run pytest $(TEST) ; \ EXIT_CODE=$$?; \ @@ -74,13 +90,12 @@ fi test_parallel: - make start-services &&\ - make start-dev-server &&\ - uv run pytest -n auto --dist worksteal $(TEST) -vv --lf; \ - EXIT_CODE=$$?; \ - make stop-services; \ - make stop-dev-server; \ - exit $$EXIT_CODE + trap '$(MAKE) stop-dev-server; $(MAKE) stop-services' EXIT; \ + trap 'exit 130' INT; trap 'exit 143' TERM; \ + $(MAKE) start-services &&\ + $(MAKE) start-dev-server &&\ + uv run --no-sync pytest -n auto --dist worksteal $(TEST) -vv --lf; \ + exit $$? integration_tests: uv run pytest integration_tests diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/PKG-INFO new/langgraph-1.2.17/PKG-INFO --- old/langgraph-1.2.16/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/PKG-INFO 2020-02-02 01:00:00.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.5 Name: langgraph -Version: 1.2.16 +Version: 1.2.17 Summary: Building stateful, multi-actor applications with LLMs Project-URL: Homepage, https://docs.langchain.com/oss/python/langgraph/overview Project-URL: Documentation, https://reference.langchain.com/python/langgraph/ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/langgraph/_internal/_config.py new/langgraph-1.2.17/langgraph/_internal/_config.py --- old/langgraph-1.2.16/langgraph/_internal/_config.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/langgraph/_internal/_config.py 2020-02-02 01:00:00.000000000 +0100 @@ -29,7 +29,19 @@ NS_SEP, ) -DEFAULT_RECURSION_LIMIT = int(getenv("LANGGRAPH_DEFAULT_RECURSION_LIMIT", "10007")) + +class _DefaultRecursionLimit(int): + """The limit `ensure_config` fills in when none is given. + + `merge_configs` skips values of this type rather than any equal value, so an + explicit limit that happens to equal the default still applies. It checks the + type, not identity, because copying or pickling a config rebuilds the value. + """ + + +DEFAULT_RECURSION_LIMIT = _DefaultRecursionLimit( + getenv("LANGGRAPH_DEFAULT_RECURSION_LIMIT", "10007") +) DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT = int( getenv("LANGGRAPH_DELTA_MAX_SUPERSTEPS_SINCE_SNAPSHOT", "5000") ) @@ -182,7 +194,7 @@ base.get("callbacks"), cast(Callbacks, value) ) elif key == "recursion_limit": - if config["recursion_limit"] != DEFAULT_RECURSION_LIMIT: + if not isinstance(config["recursion_limit"], _DefaultRecursionLimit): base["recursion_limit"] = config["recursion_limit"] else: base[key] = config[key] # type: ignore[literal-required] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/langgraph/pregel/remote.py new/langgraph-1.2.17/langgraph/pregel/remote.py --- old/langgraph-1.2.16/langgraph/pregel/remote.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/langgraph/pregel/remote.py 2020-02-02 01:00:00.000000000 +0100 @@ -861,11 +861,6 @@ ) yield {"type": mode, "ns": ns, "data": chunk.data, "interrupts": ints} elif subgraphs: - if NS_SEP in chunk.event: - mode, ns_ = chunk.event.split(NS_SEP, 1) - ns = tuple(ns_.split(NS_SEP)) - else: - mode, ns = chunk.event, () if req_single: yield ns, chunk.data else: @@ -1016,11 +1011,6 @@ ) yield {"type": mode, "ns": ns, "data": chunk.data, "interrupts": ints} elif subgraphs: - if NS_SEP in chunk.event: - mode, ns_ = chunk.event.split(NS_SEP, 1) - ns = tuple(ns_.split(NS_SEP)) - else: - mode, ns = chunk.event, () if req_single: yield ns, chunk.data else: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/pyproject.toml new/langgraph-1.2.17/pyproject.toml --- old/langgraph-1.2.16/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/pyproject.toml 2020-02-02 01:00:00.000000000 +0100 @@ -4,7 +4,7 @@ [project] name = "langgraph" -version = "1.2.16" +version = "1.2.17" description = "Building stateful, multi-actor applications with LLMs" authors = [] requires-python = ">=3.10" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/tests/test_config_async.py new/langgraph-1.2.17/tests/test_config_async.py --- old/langgraph-1.2.16/tests/test_config_async.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/tests/test_config_async.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,11 +1,19 @@ +from collections.abc import Callable + import pytest from langchain_core.callbacks import AsyncCallbackManager, BaseCallbackHandler -from langgraph._internal._config import get_async_callback_manager_for_config +from langgraph._internal._config import ( + DEFAULT_RECURSION_LIMIT, + get_async_callback_manager_for_config, +) from langgraph.graph import StateGraph +from langgraph.pregel import Pregel pytestmark = pytest.mark.anyio +EXPLICIT_DEFAULT_LIMIT = int(DEFAULT_RECURSION_LIMIT) + def test_new_async_manager_includes_tags() -> None: config = {"callbacks": None} @@ -114,3 +122,27 @@ await graph.ainvoke({}, {"tags": ["invoke"]}) assert "bound" in captured, "bound tag was dropped by ensure_config overwrite" assert "invoke" in captured, "invoke-time tag not present" + + [email protected]( + "rebind", + [ + lambda g: g.with_config(recursion_limit=EXPLICIT_DEFAULT_LIMIT), + lambda g: g.with_config({"recursion_limit": EXPLICIT_DEFAULT_LIMIT}), + lambda g: g.with_config( + {"recursion_limit": 1}, recursion_limit=EXPLICIT_DEFAULT_LIMIT + ), + lambda g: g.with_config(recursion_limit=EXPLICIT_DEFAULT_LIMIT).with_config( + tags=["t"] + ), + ], + ids=["kwarg", "config", "kwarg_over_config", "kept_by_later_with_config"], +) +def test_with_config_applies_recursion_limit_equal_to_default( + rebind: Callable[[Pregel], Pregel], +) -> None: + builder = StateGraph(dict) + builder.add_node("node", lambda state: state) + builder.add_edge("__start__", "node") + graph = builder.compile().with_config(recursion_limit=EXPLICIT_DEFAULT_LIMIT + 1) + assert rebind(graph).config["recursion_limit"] == EXPLICIT_DEFAULT_LIMIT diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/tests/test_prune_postgres.py new/langgraph-1.2.17/tests/test_prune_postgres.py --- old/langgraph-1.2.16/tests/test_prune_postgres.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/tests/test_prune_postgres.py 2020-02-02 01:00:00.000000000 +0100 @@ -2,6 +2,7 @@ import sys from collections.abc import Callable from contextlib import contextmanager +from threading import Event from typing import Annotated, Any import pytest @@ -72,12 +73,15 @@ ask: bool = False, fail: set[str] | None = None, calls: dict[str, int] | None = None, + before_fail: Callable[[], None] | None = None, ) -> Any: def note(name: str): def node(state: State) -> dict: if calls is not None: calls[name] = calls.get(name, 0) + 1 if fail is not None and name in fail: + if before_fail is not None: + before_fail() fail.discard(name) raise ValueError(f"{name} failed") return {"notes": [name]} @@ -234,18 +238,37 @@ @pytest.mark.parametrize("make_checkpointer", SYNC) def test_keep_latest_keeps_writes_of_tasks_that_finished_before_a_failure( - make_checkpointer: Any, + make_checkpointer: Any, monkeypatch: pytest.MonkeyPatch ) -> None: with make_checkpointer() as checkpointer: calls: dict[str, int] = {} fail: set[str] = set() - graph = _graph(checkpointer, fail=fail, calls=calls) + left_persisted = Event() + put_writes = checkpointer.put_writes + + def persist(config, writes, task_id, task_path=""): + put_writes(config, writes, task_id, task_path) + if ("notes", ["left"]) in writes: + left_persisted.set() + + def wait_for_left() -> None: + assert left_persisted.wait(5), "left task writes were not persisted" + + monkeypatch.setattr(checkpointer, "put_writes", persist) + graph = _graph(checkpointer, fail=fail, calls=calls, before_fail=wait_for_left) for thread_id in ("pruned", "twin"): for i in range(2): graph.invoke(_say(i), _config(thread_id)) + left_persisted.clear() fail.add("right") with pytest.raises(ValueError, match="right failed"): graph.invoke(_say(2), _config(thread_id)) + checkpoint = checkpointer.get_tuple(_config(thread_id)) + assert checkpoint is not None + assert any( + channel == "notes" and value == ["left"] + for _, channel, value in checkpoint.pending_writes + ) before = graph.get_state(_config("pruned")) checkpointer.prune(["pruned"]) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/tests/test_remote_graph.py new/langgraph-1.2.17/tests/test_remote_graph.py --- old/langgraph-1.2.16/tests/test_remote_graph.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/tests/test_remote_graph.py 2020-02-02 01:00:00.000000000 +0100 @@ -819,6 +819,50 @@ ] +_CALLER_CONFIG: RunnableConfig = { + "configurable": {"thread_id": "thread_1", "checkpoint_ns": "outer:123"} +} +_SUBGRAPH_PARTS = [ + StreamPart(event="values|sub:abc", data={"chunk": "inner"}), + StreamPart(event="values", data={"chunk": "root"}), +] +_CALLER_PREFIXED = [ + (("outer:123", "sub:abc"), {"chunk": "inner"}), + (("outer:123",), {"chunk": "root"}), +] + + +def test_stream_subgraphs_keeps_caller_namespace(): + mock_sync_client = MagicMock() + mock_sync_client.runs.stream.return_value = _SUBGRAPH_PARTS + remote_pregel = RemoteGraph("test_graph_id", sync_client=mock_sync_client) + + stream_parts = list( + remote_pregel.stream( + {"input": "data"}, _CALLER_CONFIG, stream_mode="values", subgraphs=True + ) + ) + + assert stream_parts == _CALLER_PREFIXED + + +async def test_astream_subgraphs_keeps_caller_namespace(): + mock_async_client = MagicMock() + async_iter = MagicMock() + async_iter.__aiter__.return_value = _SUBGRAPH_PARTS + mock_async_client.runs.stream.return_value = async_iter + remote_pregel = RemoteGraph("test_graph_id", client=mock_async_client) + + stream_parts = [ + part + async for part in remote_pregel.astream( + {"input": "data"}, _CALLER_CONFIG, stream_mode="values", subgraphs=True + ) + ] + + assert stream_parts == _CALLER_PREFIXED + + def test_invoke(): # set up test mock_sync_client = MagicMock() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/tests/test_utils.py new/langgraph-1.2.17/tests/test_utils.py --- old/langgraph-1.2.16/tests/test_utils.py 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/tests/test_utils.py 2020-02-02 01:00:00.000000000 +0100 @@ -1,4 +1,6 @@ +import copy import functools +import pickle import sys import uuid from collections.abc import Callable @@ -25,6 +27,7 @@ from typing_extensions import NotRequired, Required, TypedDict from langgraph._internal._config import ( + DEFAULT_RECURSION_LIMIT, _is_not_empty, _merge_callbacks, ensure_config, @@ -620,6 +623,30 @@ assert merged["metadata"]["lc_agent_name"] == "agent" [email protected]( + "rebuild", + [ + lambda config: config, + copy.deepcopy, + lambda config: pickle.loads(pickle.dumps(config)), + ], + ids=["as_is", "deepcopy", "pickle"], +) +def test_merge_configs_skips_the_injected_default_recursion_limit( + rebuild: Callable[[RunnableConfig], RunnableConfig], +) -> None: + merged = merge_configs({"recursion_limit": 50}, rebuild(ensure_config())) + assert merged["recursion_limit"] == 50 + + +def test_merge_configs_applies_an_explicit_recursion_limit_equal_to_default() -> None: + explicit_default = int(DEFAULT_RECURSION_LIMIT) + merged = merge_configs( + {"recursion_limit": 50}, {"recursion_limit": explicit_default} + ) + assert merged["recursion_limit"] == explicit_default + + def test_ensure_config_merges_metadata_lc_versions() -> None: a = { "metadata": { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/langgraph-1.2.16/uv.lock new/langgraph-1.2.17/uv.lock --- old/langgraph-1.2.16/uv.lock 2020-02-02 01:00:00.000000000 +0100 +++ new/langgraph-1.2.17/uv.lock 2020-02-02 01:00:00.000000000 +0100 @@ -202,11 +202,11 @@ [[package]] name = "certifi" -version = "2026.1.4" +version = "2026.10.19" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/2d/a891ca51311197f6ad14a7ef42e2399f36cf2f9bd44752b3dc4eab60fdc5/certifi-2026.1.4.tar.gz", hash = "sha256:ac726dd470482006e014ad384921ed6438c457018f4b3d204aea4281258b2120", size = 154268, upload-time = "2026-01-04T02:42:41.825Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a6/bd/1436c50cc46699de0230fbaacc1d1de7bfec413176099949e9d5112e88f2/certifi-2026.10.19.tar.gz", hash = "sha256:035c1e85572b141bf1c3a3eff0e33a8eb74917522f2559075ff8d2fea780a1ae", size = 137598, upload-time = "2026-10-20T02:24:16.604Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, + { url = "https://files.pythonhosted.org/packages/c4/51/29046e48f693c54e5b7412216d447a1d8362c9653148d98c02cdf65fa733/certifi-2026.10.19-py3-none-any.whl", hash = "sha256:42d35340cc5b9ba78e818ddbff0c5b1c2b779de448a340fd1b989f5fa8670e1b", size = 136464, upload-time = "2026-10-20T02:24:15.072Z" }, ] [[package]] @@ -1451,7 +1451,7 @@ [[package]] name = "langgraph" -version = "1.2.16" +version = "1.2.17" source = { editable = "." } dependencies = [ { name = "langchain-core" }, @@ -1856,7 +1856,7 @@ { name = "langgraph-checkpoint", editable = "../checkpoint" }, { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, - { name = "psycopg-binary" }, + { name = "psycopg", extras = ["binary"] }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-mock" }, @@ -1876,7 +1876,7 @@ { name = "langgraph-checkpoint", editable = "../checkpoint" }, { name = "langgraph-checkpoint-postgres", editable = "../checkpoint-postgres" }, { name = "langgraph-checkpoint-sqlite", editable = "../checkpoint-sqlite" }, - { name = "psycopg-binary" }, + { name = "psycopg", extras = ["binary"] }, { name = "pytest" }, { name = "pytest-asyncio" }, { name = "pytest-mock" }, @@ -1919,7 +1919,7 @@ { name = "langchain-core", specifier = ">=1.4.0,<2" }, { name = "langchain-protocol", specifier = ">=0.0.15" }, { name = "orjson", specifier = ">=3.11.5" }, - { name = "websockets", specifier = ">=14,<17" }, + { name = "websockets", specifier = ">=14" }, ] [package.metadata.requires-dev]
