Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-langchain-core for
openSUSE:Factory checked in at 2026-10-09 21:45:23
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langchain-core (Old)
and /work/SRC/openSUSE:Factory/.python-langchain-core.new.3698736 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-langchain-core"
Fri Oct 9 21:45:23 2026 rev:19 rq:1383683 version:1.6.9
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-langchain-core/python-langchain-core.changes
2026-10-08 12:00:19.634322775 +0200
+++
/work/SRC/openSUSE:Factory/.python-langchain-core.new.3698736/python-langchain-core.changes
2026-10-09 21:45:29.015570991 +0200
@@ -1,0 +2,7 @@
+Fri Oct 9 06:55:05 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to version 1.6.9:
+ * Harden scoped and compatible IPv6 SSRF checks
+ * with_retry now accepts a callable for retry_if_exception_type
+
+-------------------------------------------------------------------
Old:
----
langchain_core-1.6.7.tar.gz
New:
----
langchain_core-1.6.9.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-langchain-core.spec ++++++
--- /var/tmp/diff_new_pack.vmOHV7/_old 2026-10-09 21:45:29.818604782 +0200
+++ /var/tmp/diff_new_pack.vmOHV7/_new 2026-10-09 21:45:29.820604866 +0200
@@ -17,7 +17,7 @@
Name: python-langchain-core
-Version: 1.6.7
+Version: 1.6.9
Release: 0
Summary: Building applications with LLMs through composability
License: MIT
++++++ langchain_core-1.6.7.tar.gz -> langchain_core-1.6.9.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_core-1.6.7/PKG-INFO
new/langchain_core-1.6.9/PKG-INFO
--- old/langchain_core-1.6.7/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/PKG-INFO 2020-02-02 01:00:00.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.5
Name: langchain-core
-Version: 1.6.7
+Version: 1.6.9
Summary: Building applications with LLMs through composability
Project-URL: Homepage, https://docs.langchain.com/
Project-URL: Documentation,
https://reference.langchain.com/python/langchain_core/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_core-1.6.7/langchain_core/_security/_policy.py
new/langchain_core-1.6.9/langchain_core/_security/_policy.py
--- old/langchain_core-1.6.7/langchain_core/_security/_policy.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/langchain_core/_security/_policy.py
2020-02-02 01:00:00.000000000 +0100
@@ -88,6 +88,7 @@
_LOOPBACK_IPV4 = ipaddress.IPv4Network("127.0.0.0/8")
_LOOPBACK_IPV6 = ipaddress.IPv6Address("::1")
+_IPV4_COMPATIBLE_PREFIX = ipaddress.IPv6Network("::/96")
# NAT64 well-known prefixes
_NAT64_PREFIX = ipaddress.IPv6Network("64:ff9b::/96")
@@ -125,7 +126,7 @@
def _extract_embedded_ipv4(
addr: ipaddress.IPv6Address,
) -> ipaddress.IPv4Address | None:
- """Extract an embedded IPv4 from IPv4-mapped or NAT64 IPv6 addresses."""
+ """Extract IPv4 from mapped, compatible, or NAT64 IPv6 addresses."""
# Check ipv4_mapped first (covers ::ffff:x.x.x.x)
if addr.ipv4_mapped is not None:
return addr.ipv4_mapped
@@ -135,6 +136,9 @@
raw = addr.packed
return ipaddress.IPv4Address(raw[-4:])
+ if addr in _IPV4_COMPATIBLE_PREFIX and int(addr) > 1:
+ return ipaddress.IPv4Address(int(addr))
+
return None
@@ -203,6 +207,7 @@
raise SSRFBlockedError(msg) from exc
if isinstance(addr, ipaddress.IPv6Address):
+ addr = ipaddress.IPv6Address(int(addr))
inner = _extract_embedded_ipv4(addr)
if inner is not None:
addr = inner
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_core-1.6.7/langchain_core/runnables/base.py
new/langchain_core-1.6.9/langchain_core/runnables/base.py
--- old/langchain_core-1.6.7/langchain_core/runnables/base.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/langchain_core/runnables/base.py 2020-02-02
01:00:00.000000000 +0100
@@ -2102,7 +2102,8 @@
def with_retry(
self,
*,
- retry_if_exception_type: tuple[type[BaseException], ...] =
(Exception,),
+ retry_if_exception_type: tuple[type[BaseException], ...]
+ | Callable[[BaseException], bool] = (Exception,),
wait_exponential_jitter: bool = True,
exponential_jitter_params: ExponentialJitterParams | None = None,
stop_after_attempt: int = 3,
@@ -2110,7 +2111,9 @@
"""Create a new `Runnable` that retries the original `Runnable` on
exceptions.
Args:
- retry_if_exception_type: A tuple of exception types to retry on.
+ retry_if_exception_type: A tuple of exception types to retry on,
or a
+ callable that receives the raised exception and returns
whether to
+ retry it.
wait_exponential_jitter: Whether to add jitter to the wait
time between retries.
stop_after_attempt: The maximum number of attempts to make before
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_core-1.6.7/langchain_core/runnables/retry.py
new/langchain_core-1.6.9/langchain_core/runnables/retry.py
--- old/langchain_core-1.6.7/langchain_core/runnables/retry.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/langchain_core/runnables/retry.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,5 +1,6 @@
"""`Runnable` that retries a `Runnable` if it fails."""
+from collections.abc import Callable
from typing import (
TYPE_CHECKING,
Any,
@@ -12,6 +13,7 @@
RetryCallState,
RetryError,
Retrying,
+ retry_if_exception,
retry_if_exception_type,
stop_after_attempt,
wait_exponential_jitter,
@@ -111,8 +113,11 @@
```
"""
- retry_exception_types: tuple[type[BaseException], ...] = (Exception,)
- """The exception types to retry on. By default all exceptions are retried.
+ retry_exception_types: (
+ tuple[type[BaseException], ...] | Callable[[BaseException], bool]
+ ) = (Exception,)
+ """The exception types to retry on, or a callable that receives the raised
+ exception and returns whether to retry it. By default all exceptions are
retried.
In general you should only retry on exceptions that are likely to be
transient, such as network errors.
@@ -144,7 +149,9 @@
**(self.exponential_jitter_params or {})
)
- if self.retry_exception_types:
+ if callable(self.retry_exception_types):
+ kwargs["retry"] = retry_if_exception(self.retry_exception_types)
+ elif self.retry_exception_types:
kwargs["retry"] =
retry_if_exception_type(self.retry_exception_types)
return kwargs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_core-1.6.7/langchain_core/version.py
new/langchain_core-1.6.9/langchain_core/version.py
--- old/langchain_core-1.6.7/langchain_core/version.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/langchain_core/version.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,3 +1,3 @@
"""Version information for `langchain-core`."""
-VERSION = "1.6.7"
+VERSION = "1.6.9"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_core-1.6.7/pyproject.toml
new/langchain_core-1.6.9/pyproject.toml
--- old/langchain_core-1.6.7/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
+++ new/langchain_core-1.6.9/pyproject.toml 2020-02-02 01:00:00.000000000
+0100
@@ -21,7 +21,7 @@
"Topic :: Software Development :: Libraries :: Python Modules",
]
-version = "1.6.7"
+version = "1.6.9"
requires-python = ">=3.10.0,<4.0.0"
dependencies = [
"langsmith>=0.3.45,<1.0.0",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_core-1.6.7/tests/unit_tests/runnables/test_runnable.py
new/langchain_core-1.6.9/tests/unit_tests/runnables/test_runnable.py
--- old/langchain_core-1.6.7/tests/unit_tests/runnables/test_runnable.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/tests/unit_tests/runnables/test_runnable.py
2020-02-02 01:00:00.000000000 +0100
@@ -4126,6 +4126,60 @@
lambda_mock.reset_mock()
+def _retry_value_errors(exc: BaseException) -> bool:
+ return isinstance(exc, ValueError)
+
+
+def test_retrying_with_predicate(mocker: MockerFixture) -> None:
+ def _lambda(x: int) -> int:
+ if x == 1:
+ msg = "x is 1"
+ raise ValueError(msg)
+ msg = "x is 2"
+ raise RuntimeError(msg)
+
+ lambda_mock = mocker.Mock(side_effect=_lambda)
+ runnable = RunnableLambda(lambda_mock).with_retry(
+ stop_after_attempt=2,
+ wait_exponential_jitter=False,
+ retry_if_exception_type=_retry_value_errors,
+ )
+
+ with pytest.raises(ValueError, match="x is 1"):
+ runnable.invoke(1)
+ assert lambda_mock.call_count == 2 # retried
+ lambda_mock.reset_mock()
+
+ with pytest.raises(RuntimeError, match="x is 2"):
+ runnable.invoke(2)
+ assert lambda_mock.call_count == 1 # did not retry
+
+
+async def test_async_retrying_with_predicate(mocker: MockerFixture) -> None:
+ def _lambda(x: int) -> int:
+ if x == 1:
+ msg = "x is 1"
+ raise ValueError(msg)
+ msg = "x is 2"
+ raise RuntimeError(msg)
+
+ lambda_mock = mocker.Mock(side_effect=_lambda)
+ runnable = RunnableLambda(lambda_mock).with_retry(
+ stop_after_attempt=2,
+ wait_exponential_jitter=False,
+ retry_if_exception_type=_retry_value_errors,
+ )
+
+ with pytest.raises(ValueError, match="x is 1"):
+ await runnable.ainvoke(1)
+ assert lambda_mock.call_count == 2 # retried
+ lambda_mock.reset_mock()
+
+ with pytest.raises(RuntimeError, match="x is 2"):
+ await runnable.ainvoke(2)
+ assert lambda_mock.call_count == 1 # did not retry
+
+
def test_runnable_lambda_stream() -> None:
"""Test that stream works for both normal functions & those returning
Runnable."""
# Normal output should work
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langchain_core-1.6.7/tests/unit_tests/test_ssrf_policy_transport.py
new/langchain_core-1.6.9/tests/unit_tests/test_ssrf_policy_transport.py
--- old/langchain_core-1.6.7/tests/unit_tests/test_ssrf_policy_transport.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/tests/unit_tests/test_ssrf_policy_transport.py
2020-02-02 01:00:00.000000000 +0100
@@ -37,6 +37,40 @@
validate_resolved_ip("64:ff9b::c0a8:101", policy)
[email protected]("block_private_ips", [True, False])
[email protected](
+ "ip",
+ [
+ "fd00:ec2::254%eth0",
+ "fd00:ec2::23%eth0",
+ "fe80::a9fe:a9fe%eth0",
+ "::1%eth0",
+ "::169.254.169.254",
+ "::169.254.170.2",
+ "::100.100.100.200",
+ "::127.0.0.1",
+ ],
+)
+def test_scoped_and_compatible_ipv6_blocked(
+ ip: str, *, block_private_ips: bool
+) -> None:
+ policy = SSRFPolicy(block_private_ips=block_private_ips)
+ with pytest.raises(SSRFBlockedError):
+ validate_resolved_ip(ip, policy)
+ with pytest.raises(SSRFBlockedError):
+ validate_url_sync(f"http://[{ip}]/", policy)
+
+
[email protected]("ip", ["::8.8.8.8", "::192.168.1.1",
"fd00::123%eth0", "::"])
+def test_relaxed_policy_allows_non_metadata_ipv6(ip: str) -> None:
+ validate_resolved_ip(ip, SSRFPolicy(block_private_ips=False))
+
+
[email protected]("ip", ["::1", "::1%eth0", "::127.0.0.1"])
+def test_relaxed_policy_can_allow_ipv6_localhost(ip: str) -> None:
+ validate_resolved_ip(ip, SSRFPolicy(block_private_ips=False,
block_localhost=False))
+
+
def test_validate_resolved_ip_blocks_cgnat() -> None:
policy = SSRFPolicy()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langchain_core-1.6.7/uv.lock
new/langchain_core-1.6.9/uv.lock
--- old/langchain_core-1.6.7/uv.lock 2020-02-02 01:00:00.000000000 +0100
+++ new/langchain_core-1.6.9/uv.lock 2020-02-02 01:00:00.000000000 +0100
@@ -1087,7 +1087,7 @@
[[package]]
name = "langchain-core"
-version = "1.6.7"
+version = "1.6.9"
source = { editable = "." }
dependencies = [
{ name = "httpx" },