Script 'mail_helper' called by obssrc
Hello community,
here is the log from the commit of package python-langgraph-checkpoint for
openSUSE:Factory checked in at 2026-10-15 12:25:33
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-langgraph-checkpoint (Old)
and /work/SRC/openSUSE:Factory/.python-langgraph-checkpoint.new.3698736
(New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-langgraph-checkpoint"
Thu Oct 15 12:25:33 2026 rev:4 rq:1384876 version:4.3.0
Changes:
--------
---
/work/SRC/openSUSE:Factory/python-langgraph-checkpoint/python-langgraph-checkpoint.changes
2026-08-18 16:38:09.430525167 +0200
+++
/work/SRC/openSUSE:Factory/.python-langgraph-checkpoint.new.3698736/python-langgraph-checkpoint.changes
2026-10-15 12:25:34.505713377 +0200
@@ -1,0 +2,9 @@
+Thu Oct 15 04:40:45 UTC 2026 - Martin Pluskal <[email protected]>
+
+- Update to 4.3.0:
+ * Default InMemorySaver delta history to the latest checkpoint
+ * Validate namespace labels before store dispatch
+ * Keep serialized data when an object cannot be rebuilt
+ * Widen Store put value type to Mapping[str, Any]
+
+-------------------------------------------------------------------
Old:
----
langgraph_checkpoint-4.2.0.tar.gz
New:
----
langgraph_checkpoint-4.3.0.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-langgraph-checkpoint.spec ++++++
--- /var/tmp/diff_new_pack.CVP62L/_old 2026-10-15 12:25:35.350748737 +0200
+++ /var/tmp/diff_new_pack.CVP62L/_new 2026-10-15 12:25:35.352748820 +0200
@@ -17,7 +17,7 @@
Name: python-langgraph-checkpoint
-Version: 4.2.0
+Version: 4.3.0
Release: 0
Summary: Library with base interfaces for LangGraph checkpoint savers
License: MIT
++++++ langgraph_checkpoint-4.2.0.tar.gz -> langgraph_checkpoint-4.3.0.tar.gz
++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/.gitignore
new/langgraph_checkpoint-4.3.0/.gitignore
--- old/langgraph_checkpoint-4.2.0/.gitignore 2020-02-02 01:00:00.000000000
+0100
+++ new/langgraph_checkpoint-4.3.0/.gitignore 2020-02-02 01:00:00.000000000
+0100
@@ -76,7 +76,12 @@
# Environments
.env
+.env.*
.envrc
+*.crt
+*.key
+*.pem
+credentials.json
.venv
.venvs
env/
@@ -98,6 +103,7 @@
.vercel
.turbo
+node_modules/
.editorconfig
.scratch
.worktrees/
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/PKG-INFO
new/langgraph_checkpoint-4.3.0/PKG-INFO
--- old/langgraph_checkpoint-4.2.0/PKG-INFO 2020-02-02 01:00:00.000000000
+0100
+++ new/langgraph_checkpoint-4.3.0/PKG-INFO 2020-02-02 01:00:00.000000000
+0100
@@ -1,6 +1,6 @@
-Metadata-Version: 2.4
+Metadata-Version: 2.5
Name: langgraph-checkpoint
-Version: 4.2.0
+Version: 4.3.0
Summary: Library with base interfaces for LangGraph checkpoint savers.
Project-URL: Source,
https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint
Project-URL: Twitter, https://x.com/langchain_oss
@@ -54,7 +54,12 @@
```python
{"configurable": {"thread_id": "1"}} # valid config
-{"configurable": {"thread_id": "1", "checkpoint_id":
"0c62ca34-ac19-445d-bbb0-5b4984975b2a"}} # also valid config
+{
+ "configurable": {
+ "thread_id": "1",
+ "checkpoint_id": "0c62ca34-ac19-445d-bbb0-5b4984975b2a",
+ }
+} # also valid config
```
### Serde
@@ -94,24 +99,12 @@
"v": 4,
"ts": "2024-07-31T20:14:19.804150+00:00",
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
- "channel_values": {
- "my_key": "meow",
- "node": "node"
- },
- "channel_versions": {
- "__start__": 2,
- "my_key": 3,
- "start:node": 3,
- "node": 3
- },
+ "channel_values": {"my_key": "meow", "node": "node"},
+ "channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node":
3},
"versions_seen": {
- "__input__": {},
- "__start__": {
- "__start__": 1
- },
- "node": {
- "start:node": 2
- }
+ "__input__": {},
+ "__start__": {"__start__": 1},
+ "node": {"start:node": 2},
},
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/README.md
new/langgraph_checkpoint-4.3.0/README.md
--- old/langgraph_checkpoint-4.2.0/README.md 2020-02-02 01:00:00.000000000
+0100
+++ new/langgraph_checkpoint-4.3.0/README.md 2020-02-02 01:00:00.000000000
+0100
@@ -39,7 +39,12 @@
```python
{"configurable": {"thread_id": "1"}} # valid config
-{"configurable": {"thread_id": "1", "checkpoint_id":
"0c62ca34-ac19-445d-bbb0-5b4984975b2a"}} # also valid config
+{
+ "configurable": {
+ "thread_id": "1",
+ "checkpoint_id": "0c62ca34-ac19-445d-bbb0-5b4984975b2a",
+ }
+} # also valid config
```
### Serde
@@ -79,24 +84,12 @@
"v": 4,
"ts": "2024-07-31T20:14:19.804150+00:00",
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
- "channel_values": {
- "my_key": "meow",
- "node": "node"
- },
- "channel_versions": {
- "__start__": 2,
- "my_key": 3,
- "start:node": 3,
- "node": 3
- },
+ "channel_values": {"my_key": "meow", "node": "node"},
+ "channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node":
3},
"versions_seen": {
- "__input__": {},
- "__start__": {
- "__start__": 1
- },
- "node": {
- "start:node": 2
- }
+ "__input__": {},
+ "__start__": {"__start__": 1},
+ "node": {"start:node": 2},
},
}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/base/__init__.py
new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/base/__init__.py
--- old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/base/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/base/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -10,6 +10,7 @@
NamedTuple,
TypedDict,
TypeVar,
+ cast,
)
from langchain_core.runnables import RunnableConfig
@@ -161,6 +162,14 @@
Always present; possibly empty. Already filtered to one channel.
Writes stored at the target checkpoint itself are pending for the
next super-step and are excluded.
+
+ Within a single checkpoint, writes are ordered by `writes_sort_key`,
+ `(task_path, task_id, idx)`, which is the order live execution applies
+ a super-step's task writes in. `task_id` is a hash of the path, so
+ ordering by it permutes parallel tasks writing one channel, and
+ reducers need not be order-invariant. Writes stored without a
+ `task_path` (graph input, `update_state` and `Command` updates, rows
+ predating the column) sort first, by `task_id`.
* `seed` — the stored value at the nearest ancestor whose
`channel_values[ch]` is populated. Omitted if the walk reached the
root without finding any stored value (consumer treats absence as
@@ -173,6 +182,20 @@
seed: NotRequired[Any]
+def writes_sort_key(
+ task_path: str, task_id: str = "", idx: int = 0
+) -> tuple[str, str, int]:
+ """Sort key for the writes of one super-step.
+
+ Live execution applies a super-step's tasks in this order, so a saver
+ that replays stored writes, as `get_delta_channel_history` does, must
+ sort them by it too, or an order-sensitive reducer rebuilds a different
+ value than the run produced. `task_path` is the string passed to
+ `put_writes`.
+ """
+ return (task_path, task_id, idx)
+
+
class BaseCheckpointSaver(Generic[V]):
"""Base class for creating a graph checkpointer.
@@ -243,7 +266,8 @@
config: Configuration specifying which checkpoint to retrieve.
Returns:
- The requested checkpoint tuple, or `None` if not found.
+ The requested checkpoint tuple, or `None` if not found. Its
+ `pending_writes` must be in `writes_sort_key` order.
Raises:
NotImplementedError: Implement this method in your custom
checkpoint saver.
@@ -433,7 +457,8 @@
config: Configuration specifying which checkpoint to retrieve.
Returns:
- The requested checkpoint tuple, or `None` if not found.
+ The requested checkpoint tuple, or `None` if not found. Its
+ `pending_writes` must be in `writes_sort_key` order.
Raises:
NotImplementedError: Implement this method in your custom
checkpoint saver.
@@ -610,6 +635,10 @@
`PostgresSaver`) override for performance; the return contract is
fixed here.
+ `PendingWrite` carries no `task_path`, so this default replays each
+ checkpoint's writes in `get_tuple`'s `pending_writes` order, which
+ `get_tuple` must return in `writes_sort_key` order.
+
Args:
config: Configuration identifying the target checkpoint.
channels: Channel names to walk for. Empty → empty mapping.
@@ -781,7 +810,7 @@
"""Get checkpoint metadata in a backwards-compatible manner."""
checkpoint_metadata = get_checkpoint_metadata(config, metadata)
if "writes" in checkpoint_metadata:
- checkpoint_metadata.pop("writes")
+ cast(dict[str, Any], checkpoint_metadata).pop("writes")
return checkpoint_metadata
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/memory/__init__.py
new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/memory/__init__.py
--- old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/memory/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/memory/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -25,6 +25,7 @@
SerializerProtocol,
get_checkpoint_id,
get_checkpoint_metadata,
+ writes_sort_key,
)
logger = logging.getLogger(__name__)
@@ -139,6 +140,15 @@
result[k] = self.serde.loads_typed(vv)
return result
+ def _ordered_writes(
+ self, thread_id: str, checkpoint_ns: str, checkpoint_id: str
+ ) -> list[tuple[str, str, tuple[str, bytes], str]]:
+ stored = self.writes.get((thread_id, checkpoint_ns, checkpoint_id), {})
+ return [
+ stored[k]
+ for k in sorted(stored, key=lambda k:
writes_sort_key(stored[k][3], *k))
+ ]
+
def get_delta_channel_history(
self, *, config: RunnableConfig, channels: Sequence[str]
) -> Mapping[str, DeltaChannelHistory]:
@@ -160,8 +170,8 @@
return {}
thread_id = config["configurable"]["thread_id"]
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
- checkpoint_id = config["configurable"].get("checkpoint_id", "")
ns_storage = self.storage.get(thread_id, {}).get(checkpoint_ns, {})
+ checkpoint_id = get_checkpoint_id(config) or max(ns_storage,
default="")
chain: list[str] = []
target_entry = ns_storage.get(checkpoint_id)
@@ -198,9 +208,8 @@
blob_value_by_ch[ch] = self.serde.loads_typed(blob_entry)
terminated_here.add(ch)
- step_writes = self.writes.get((thread_id, checkpoint_ns, cp_id),
{})
- for (_task_id, _idx), (tid, ch, serialized, _) in sorted(
- step_writes.items(), reverse=True
+ for tid, ch, serialized, _ in reversed(
+ self._ordered_writes(thread_id, checkpoint_ns, cp_id)
):
if ch not in remaining:
continue
@@ -246,7 +255,7 @@
if checkpoint_id := get_checkpoint_id(config):
if saved :=
self.storage[thread_id][checkpoint_ns].get(checkpoint_id):
checkpoint, metadata, parent_checkpoint_id = saved
- writes = self.writes[(thread_id, checkpoint_ns,
checkpoint_id)].values()
+ writes = self._ordered_writes(thread_id, checkpoint_ns,
checkpoint_id)
checkpoint_: Checkpoint = self.serde.loads_typed(checkpoint)
return CheckpointTuple(
config=config,
@@ -276,7 +285,7 @@
if checkpoints := self.storage[thread_id][checkpoint_ns]:
checkpoint_id = max(checkpoints.keys())
checkpoint, metadata, parent_checkpoint_id =
checkpoints[checkpoint_id]
- writes = self.writes[(thread_id, checkpoint_ns,
checkpoint_id)].values()
+ writes = self._ordered_writes(thread_id, checkpoint_ns,
checkpoint_id)
checkpoint_ = self.serde.loads_typed(checkpoint)
return CheckpointTuple(
config={
@@ -379,9 +388,9 @@
elif limit is not None:
limit -= 1
- writes = self.writes[
- (thread_id, checkpoint_ns, checkpoint_id)
- ].values()
+ writes = self._ordered_writes(
+ thread_id, checkpoint_ns, checkpoint_id
+ )
checkpoint_: Checkpoint =
self.serde.loads_typed(checkpoint)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/serde/jsonplus.py
new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/serde/jsonplus.py
--- old/langgraph_checkpoint-4.2.0/langgraph/checkpoint/serde/jsonplus.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/checkpoint/serde/jsonplus.py
2020-02-02 01:00:00.000000000 +0100
@@ -55,6 +55,7 @@
_MAX_WARNED_TYPES = 1000
_warned_unregistered_types: set[tuple[str, str]] = set()
_warned_blocked_types: set[tuple[str, str]] = set()
+_warned_unreconstructable_types: set[tuple[str, str]] = set()
def _is_safe_json_type(id_list: list[str]) -> bool:
@@ -79,6 +80,27 @@
logger.warning(msg, *args)
+def _reconstruction_fallback(tup: Any, exc: Exception) -> Any:
+ """Return the serialized payload of an object that could not be rebuilt.
+
+ Returning `None` here would silently erase the value from restored state.
+ """
+ try:
+ module, name, payload = tup[0], tup[1], tup[2]
+ except Exception:
+ return None
+ _warn_once(
+ _warned_unreconstructable_types,
+ (str(module), str(name)),
+ "Could not reconstruct %s.%s from checkpoint (%s); "
+ "returning its serialized data instead.",
+ module,
+ name,
+ type(exc).__name__,
+ )
+ return payload
+
+
class JsonPlusSerializer(SerializerProtocol):
"""Serializer that uses ormsgpack, with optional fallbacks.
@@ -638,6 +660,7 @@
)
)
elif code == EXT_CONSTRUCTOR_SINGLE_ARG:
+ tup = None
try:
tup = ormsgpack.unpackb(
data, ext_hook=ext_hook, option=ormsgpack.OPT_NON_STR_KEYS
@@ -649,9 +672,10 @@
return tup[2]
# module, name, arg
return getattr(importlib.import_module(tup[0]), tup[1])(tup[2])
- except Exception:
- return None
+ except Exception as exc:
+ return _reconstruction_fallback(tup, exc)
elif code == EXT_CONSTRUCTOR_POS_ARGS:
+ tup = None
try:
tup = ormsgpack.unpackb(
data, ext_hook=ext_hook, option=ormsgpack.OPT_NON_STR_KEYS
@@ -662,9 +686,10 @@
return _send_from_args(tup[2])
# module, name, args
return getattr(importlib.import_module(tup[0]),
tup[1])(*tup[2])
- except Exception:
- return None
+ except Exception as exc:
+ return _reconstruction_fallback(tup, exc)
elif code == EXT_CONSTRUCTOR_KW_ARGS:
+ tup = None
try:
tup = ormsgpack.unpackb(
data, ext_hook=ext_hook, option=ormsgpack.OPT_NON_STR_KEYS
@@ -673,9 +698,10 @@
return tup[2]
# module, name, kwargs
return getattr(importlib.import_module(tup[0]),
tup[1])(**tup[2])
- except Exception:
- return None
+ except Exception as exc:
+ return _reconstruction_fallback(tup, exc)
elif code == EXT_METHOD_SINGLE_ARG:
+ tup = None
try:
tup = ormsgpack.unpackb(
data, ext_hook=ext_hook, option=ormsgpack.OPT_NON_STR_KEYS
@@ -686,8 +712,8 @@
return getattr(
getattr(importlib.import_module(tup[0]), tup[1]), tup[3]
)(tup[2])
- except Exception:
- return None
+ except Exception as exc:
+ return _reconstruction_fallback(tup, exc)
elif code == EXT_PYDANTIC_V1:
try:
tup = ormsgpack.unpackb(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/store/base/__init__.py
new/langgraph_checkpoint-4.3.0/langgraph/store/base/__init__.py
--- old/langgraph_checkpoint-4.2.0/langgraph/store/base/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/store/base/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -12,7 +12,7 @@
from __future__ import annotations
from abc import ABC, abstractmethod
-from collections.abc import Iterable
+from collections.abc import Iterable, Mapping
from datetime import datetime
from typing import (
Any,
@@ -473,10 +473,10 @@
the full path would effectively be `"documents/user123/report1"`
"""
- value: dict[str, Any] | None
+ value: Mapping[str, Any] | None
"""The data to store, or `None` to mark the item for deletion.
- The value must be a dictionary with string keys and JSON-serializable
values.
+ The value must be a mapping with string keys and JSON-serializable values.
Setting this to `None` signals that the item should be deleted.
Example:
@@ -771,7 +771,12 @@
Returns:
The retrieved item or `None` if not found.
+
+ Raises:
+ InvalidNamespaceError: If a namespace label is empty, is not a
string,
+ or contains a period (`.`).
"""
+ _validate_namespace_labels(namespace)
return self.batch(
[GetOp(namespace, str(key), _ensure_refresh(self.ttl_config,
refresh_ttl))]
)[0]
@@ -801,6 +806,10 @@
Returns:
List of items matching the search criteria.
+ Raises:
+ InvalidNamespaceError: If a `namespace_prefix` label is empty, is
not a
+ string, or contains a period (`.`).
+
???+ example "Examples"
Basic filtering:
@@ -840,6 +849,7 @@
Natural language search support depends on your store
implementation
and requires proper embedding configuration.
"""
+ _validate_namespace_labels(namespace_prefix)
return self.batch(
[
SearchOp(
@@ -857,7 +867,7 @@
self,
namespace: tuple[str, ...],
key: str,
- value: dict[str, Any],
+ value: Mapping[str, Any],
index: Literal[False] | list[str] | None = None,
*,
ttl: float | None | NotProvided = NOT_PROVIDED,
@@ -869,7 +879,7 @@
Example: `("documents", "user123")`
key: Unique identifier within the namespace. Together with
namespace forms
the complete path to the item.
- value: Dictionary containing the item's data. Must contain string
keys
+ value: Mapping containing the item's data. Must contain string keys
and JSON-serializable values.
index: Controls how the item's fields are indexed for search:
@@ -887,6 +897,11 @@
By default, the expiration timer refreshes on both read
operations (get/search)
and write operations (put/update), whenever the item is
included in the operation.
+ Raises:
+ InvalidNamespaceError: If the namespace is empty, its root label is
+ `"langgraph"`, or a label is empty, is not a string, or
contains a
+ period (`.`).
+
Note:
Indexing support depends on your store implementation.
If you do not initialize the store with indexing capabilities,
@@ -940,7 +955,12 @@
Args:
namespace: Hierarchical path for the item.
key: Unique identifier within the namespace.
+
+ Raises:
+ InvalidNamespaceError: If a namespace label is empty, is not a
string,
+ or contains a period (`.`).
"""
+ _validate_namespace_labels(namespace)
self.batch([PutOp(namespace, str(key), None, ttl=None)])
def list_namespaces(
@@ -969,6 +989,10 @@
A list of namespace tuples that match the criteria. Each tuple
represents a
full namespace path up to `max_depth`.
+ Raises:
+ InvalidNamespaceError: If a `prefix` or `suffix` label is empty,
is not a
+ string, or contains a period (`.`).
+
???+ example "Examples":
Setting `max_depth=3`. Given the namespaces:
@@ -984,6 +1008,8 @@
# [("a", "b", "c"), ("a", "b", "d"), ("a", "b", "f")]
```
"""
+ _validate_namespace_labels(prefix or ())
+ _validate_namespace_labels(suffix or ())
match_conditions = []
if prefix:
match_conditions.append(MatchCondition(match_type="prefix",
path=prefix))
@@ -1013,7 +1039,12 @@
Returns:
The retrieved item or `None` if not found.
+
+ Raises:
+ InvalidNamespaceError: If a namespace label is empty, is not a
string,
+ or contains a period (`.`).
"""
+ _validate_namespace_labels(namespace)
return (
await self.abatch(
[
@@ -1052,6 +1083,10 @@
Returns:
List of items matching the search criteria.
+ Raises:
+ InvalidNamespaceError: If a `namespace_prefix` label is empty, is
not a
+ string, or contains a period (`.`).
+
???+ example "Examples"
Basic filtering:
@@ -1091,6 +1126,7 @@
Natural language search support depends on your store
implementation
and requires proper embedding configuration.
"""
+ _validate_namespace_labels(namespace_prefix)
return (
await self.abatch(
[
@@ -1110,7 +1146,7 @@
self,
namespace: tuple[str, ...],
key: str,
- value: dict[str, Any],
+ value: Mapping[str, Any],
index: Literal[False] | list[str] | None = None,
*,
ttl: float | None | NotProvided = NOT_PROVIDED,
@@ -1122,7 +1158,7 @@
Example: `("documents", "user123")`
key: Unique identifier within the namespace. Together with
namespace forms
the complete path to the item.
- value: Dictionary containing the item's data. Must contain string
keys
+ value: Mapping containing the item's data. Must contain string keys
and JSON-serializable values.
index: Controls how the item's fields are indexed for search:
@@ -1140,6 +1176,11 @@
By default, the expiration timer refreshes on both read
operations (get/search)
and write operations (put/update), whenever the item is
included in the operation.
+ Raises:
+ InvalidNamespaceError: If the namespace is empty, its root label is
+ `"langgraph"`, or a label is empty, is not a string, or
contains a
+ period (`.`).
+
Note:
Indexing support depends on your store implementation.
If you do not initialize the store with indexing capabilities,
@@ -1201,7 +1242,12 @@
Args:
namespace: Hierarchical path for the item.
key: Unique identifier within the namespace.
+
+ Raises:
+ InvalidNamespaceError: If a namespace label is empty, is not a
string,
+ or contains a period (`.`).
"""
+ _validate_namespace_labels(namespace)
await self.abatch([PutOp(namespace, str(key), None)])
async def alist_namespaces(
@@ -1230,6 +1276,10 @@
A list of namespace tuples that match the criteria. Each tuple
represents a
full namespace path up to `max_depth`.
+ Raises:
+ InvalidNamespaceError: If a `prefix` or `suffix` label is empty,
is not a
+ string, or contains a period (`.`).
+
???+ example "Examples"
Setting `max_depth=3` with existing namespaces:
@@ -1245,6 +1295,8 @@
# Returns: [("a", "b", "c"), ("a", "b", "d"), ("a", "b", "f")]
```
"""
+ _validate_namespace_labels(prefix or ())
+ _validate_namespace_labels(suffix or ())
match_conditions = []
if prefix:
match_conditions.append(MatchCondition(match_type="prefix",
path=prefix))
@@ -1263,6 +1315,14 @@
def _validate_namespace(namespace: tuple[str, ...]) -> None:
if not namespace:
raise InvalidNamespaceError("Namespace cannot be empty.")
+ _validate_namespace_labels(namespace)
+ if namespace[0] == "langgraph":
+ raise InvalidNamespaceError(
+ f'Root label for namespace cannot be "langgraph". Got: {namespace}'
+ )
+
+
+def _validate_namespace_labels(namespace: tuple[str, ...]) -> None:
for label in namespace:
if not isinstance(label, str):
raise InvalidNamespaceError(
@@ -1277,10 +1337,27 @@
raise InvalidNamespaceError(
f"Namespace labels cannot be empty strings. Got {label} in
{namespace}"
)
- if namespace[0] == "langgraph":
- raise InvalidNamespaceError(
- f'Root label for namespace cannot be "langgraph". Got: {namespace}'
- )
+
+
+def validate_op_namespace(op: Op) -> None:
+ """Validate the namespace labels an op carries before a store executes it.
+
+ `BaseStore` methods check labels before batching, but ops passed directly
to
+ `batch`/`abatch` skip those methods. Stores that serialize namespaces as
+ delimited text should call this for every op they execute, so a label such
+ as `"foo.bar"` cannot address the namespace `("foo", "bar")`.
+
+ Raises:
+ InvalidNamespaceError: If a label is empty, is not a string, or
contains
+ a period (`.`).
+ """
+ if isinstance(op, (GetOp, PutOp)):
+ _validate_namespace_labels(op.namespace)
+ elif isinstance(op, SearchOp):
+ _validate_namespace_labels(op.namespace_prefix)
+ elif isinstance(op, ListNamespacesOp):
+ for condition in op.match_conditions or ():
+ _validate_namespace_labels(condition.path)
def _ensure_refresh(
@@ -1319,4 +1396,5 @@
"ensure_embeddings",
"tokenize_path",
"get_text_at_path",
+ "validate_op_namespace",
]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/store/base/batch.py
new/langgraph_checkpoint-4.3.0/langgraph/store/base/batch.py
--- old/langgraph_checkpoint-4.2.0/langgraph/store/base/batch.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/store/base/batch.py
2020-02-02 01:00:00.000000000 +0100
@@ -5,7 +5,7 @@
import asyncio
import functools
import weakref
-from collections.abc import Callable, Iterable
+from collections.abc import Callable, Iterable, Mapping
from typing import Any, Literal, TypeVar
from langgraph.store.base import (
@@ -25,6 +25,7 @@
_ensure_refresh,
_ensure_ttl,
_validate_namespace,
+ _validate_namespace_labels,
)
F = TypeVar("F", bound=Callable)
@@ -86,6 +87,7 @@
*,
refresh_ttl: bool | None = None,
) -> Item | None:
+ _validate_namespace_labels(namespace)
self._ensure_task()
fut = self._loop.create_future()
self._aqueue.put_nowait(
@@ -111,6 +113,7 @@
offset: int = 0,
refresh_ttl: bool | None = None,
) -> list[SearchItem]:
+ _validate_namespace_labels(namespace_prefix)
self._ensure_task()
fut = self._loop.create_future()
self._aqueue.put_nowait(
@@ -132,7 +135,7 @@
self,
namespace: tuple[str, ...],
key: str,
- value: dict[str, Any],
+ value: Mapping[str, Any],
index: Literal[False] | list[str] | None = None,
*,
ttl: float | None | NotProvided = NOT_PROVIDED,
@@ -155,6 +158,7 @@
namespace: tuple[str, ...],
key: str,
) -> None:
+ _validate_namespace_labels(namespace)
self._ensure_task()
fut = self._loop.create_future()
self._aqueue.put_nowait((fut, PutOp(namespace, key, None)))
@@ -169,6 +173,8 @@
limit: int = 100,
offset: int = 0,
) -> list[tuple[str, ...]]:
+ _validate_namespace_labels(prefix or ())
+ _validate_namespace_labels(suffix or ())
self._ensure_task()
fut = self._loop.create_future()
match_conditions = []
@@ -231,7 +237,7 @@
self,
namespace: tuple[str, ...],
key: str,
- value: dict[str, Any],
+ value: Mapping[str, Any],
index: Literal[False] | list[str] | None = None,
*,
ttl: float | None | NotProvided = NOT_PROVIDED,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/store/base/embed.py
new/langgraph_checkpoint-4.3.0/langgraph/store/base/embed.py
--- old/langgraph_checkpoint-4.2.0/langgraph/store/base/embed.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/store/base/embed.py
2020-02-02 01:00:00.000000000 +0100
@@ -11,7 +11,7 @@
import asyncio
import functools
import json
-from collections.abc import Awaitable, Callable, Sequence
+from collections.abc import Awaitable, Callable, Mapping, Sequence
from typing import Any
from langchain_core.embeddings import Embeddings
@@ -244,6 +244,9 @@
- Multi-field selection: "{field1,field2}"
- Nested paths in multi-field: "{field1,nested.field2}"
"""
+ if isinstance(obj, Mapping) and not isinstance(obj, dict):
+ obj = dict(obj)
+
if not path or path == "$":
return [json.dumps(obj, sort_keys=True, ensure_ascii=False)]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/langgraph/store/memory/__init__.py
new/langgraph_checkpoint-4.3.0/langgraph/store/memory/__init__.py
--- old/langgraph_checkpoint-4.2.0/langgraph/store/memory/__init__.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/langgraph/store/memory/__init__.py
2020-02-02 01:00:00.000000000 +0100
@@ -408,7 +408,7 @@
self._vectors[namespace].pop(key, None)
else:
self._data[namespace][key] = Item(
- value=op.value,
+ value=dict(op.value),
key=key,
namespace=namespace,
created_at=datetime.now(timezone.utc),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/pyproject.toml
new/langgraph_checkpoint-4.3.0/pyproject.toml
--- old/langgraph_checkpoint-4.2.0/pyproject.toml 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/pyproject.toml 2020-02-02
01:00:00.000000000 +0100
@@ -4,7 +4,7 @@
[project]
name = "langgraph-checkpoint"
-version = "4.2.0"
+version = "4.3.0"
description = "Library with base interfaces for LangGraph checkpoint savers."
authors = []
requires-python = ">=3.10"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/langgraph_checkpoint-4.2.0/tests/test_conformance_delta.py
new/langgraph_checkpoint-4.3.0/tests/test_conformance_delta.py
--- old/langgraph_checkpoint-4.2.0/tests/test_conformance_delta.py
2020-02-02 01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/tests/test_conformance_delta.py
1970-01-01 01:00:00.000000000 +0100
@@ -1,37 +0,0 @@
-"""Run delta-channel conformance capabilities against InMemorySaver."""
-
-from __future__ import annotations
-
-import pytest
-
-conformance = pytest.importorskip(
- "langgraph.checkpoint.conformance",
- reason="langgraph-checkpoint-conformance not installed",
-)
-
-
[email protected]
-async def test_delta_channel_conformance():
- # Imported inside the test: the module-level importorskip above is what
- # makes these safe, so they cannot move to the top of the file.
- from langgraph.checkpoint.conformance import validate # noqa: PLC0415
- from langgraph.checkpoint.conformance.initializer import ( # noqa: PLC0415
- checkpointer_test,
- )
-
- from langgraph.checkpoint.memory import InMemorySaver # noqa: PLC0415
-
- @checkpointer_test(name="InMemorySaver")
- async def mem_saver():
- yield InMemorySaver()
-
- report = await validate(
- mem_saver,
- capabilities={
- "delta_channel_history",
- },
- )
- for cap, result in report.results.items():
- if result.passed is False:
- details = "\n".join(result.failures or [])
- pytest.fail(f"Capability {cap} failed:\n{details}")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/tests/test_jsonplus.py
new/langgraph_checkpoint-4.3.0/tests/test_jsonplus.py
--- old/langgraph_checkpoint-4.2.0/tests/test_jsonplus.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/tests/test_jsonplus.py 2020-02-02
01:00:00.000000000 +0100
@@ -7,6 +7,7 @@
import re
import sys
import tempfile
+import types
import uuid
from collections import deque
from datetime import date, datetime, time, timezone
@@ -33,12 +34,16 @@
register_serde_event_listener,
)
from langgraph.checkpoint.serde.jsonplus import (
+ EXT_CONSTRUCTOR_KW_ARGS,
+ EXT_CONSTRUCTOR_POS_ARGS,
+ EXT_CONSTRUCTOR_SINGLE_ARG,
EXT_METHOD_SINGLE_ARG,
InvalidModuleError,
JsonPlusSerializer,
_msgpack_enc,
_msgpack_ext_hook_to_json,
_warned_blocked_types,
+ _warned_unreconstructable_types,
_warned_unregistered_types,
)
from langgraph.store.base import Item
@@ -821,6 +826,7 @@
# a fresh slate and assertions about warning emission are stable.
_warned_unregistered_types.clear()
_warned_blocked_types.clear()
+ _warned_unreconstructable_types.clear()
def test_msgpack_pydantic_warns_by_default(caplog: pytest.LogCaptureFixture)
-> None:
@@ -1230,3 +1236,58 @@
# No blocking should occur - inner is serialized as dict, not ext
assert "blocked" not in caplog.text.lower()
assert result == obj
+
+
+def test_msgpack_dataclass_from_removed_module_restores_payload(
+ monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture
+) -> None:
+ @dataclasses.dataclass
+ class SavedObject:
+ value: int
+
+ SavedObject.__module__ = "removed_module"
+ module = types.ModuleType("removed_module")
+ module.SavedObject = SavedObject
+ monkeypatch.setitem(sys.modules, "removed_module", module)
+ serde = JsonPlusSerializer(
+ allowed_msgpack_modules=[("removed_module", "SavedObject")]
+ )
+ dumped = serde.dumps_typed({"state": SavedObject(123)})
+ assert serde.loads_typed(dumped) == {"state": SavedObject(123)}
+
+ monkeypatch.delitem(sys.modules, "removed_module")
+ caplog.set_level(logging.WARNING,
logger="langgraph.checkpoint.serde.jsonplus")
+
+ assert serde.loads_typed(dumped) == {"state": {"value": 123}}
+ assert (
+ "could not reconstruct removed_module.savedobject from checkpoint "
+ "(modulenotfounderror)" in caplog.text.lower()
+ )
+
+
[email protected](
+ ("code", "tup", "expected"),
+ [
+ (EXT_CONSTRUCTOR_SINGLE_ARG, ("missing_module", "Thing", "x"), "x"),
+ (EXT_CONSTRUCTOR_POS_ARGS, ("missing_module", "Thing", [1, 2]), [1,
2]),
+ (
+ EXT_CONSTRUCTOR_KW_ARGS,
+ ("missing_module", "Thing", {"value": 123}),
+ {"value": 123},
+ ),
+ (
+ EXT_METHOD_SINGLE_ARG,
+ ("datetime", "datetime", "not-a-date", "fromisoformat"),
+ "not-a-date",
+ ),
+ ],
+)
+def test_msgpack_failed_reconstruction_returns_payload(
+ code: int, tup: tuple, expected: object
+) -> None:
+ serde = JsonPlusSerializer(allowed_msgpack_modules=True)
+ payload = ormsgpack.packb(
+ ormsgpack.Ext(code, _msgpack_enc(tup)),
option=ormsgpack.OPT_NON_STR_KEYS
+ )
+
+ assert serde.loads_typed(("msgpack", payload)) == expected
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/tests/test_memory.py
new/langgraph_checkpoint-4.3.0/tests/test_memory.py
--- old/langgraph_checkpoint-4.2.0/tests/test_memory.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/tests/test_memory.py 2020-02-02
01:00:00.000000000 +0100
@@ -420,6 +420,19 @@
assert "seed" not in result
assert result["writes"] == []
+ def test_get_channel_writes_without_checkpoint_id_reads_the_latest(self)
-> None:
+ saver = InMemorySaver()
+ thread: RunnableConfig = {
+ "configurable": {"thread_id": "t1", "checkpoint_ns": ""}
+ }
+ parent = saver.put(thread, empty_checkpoint(), {}, {})
+ saver.put_writes(parent, [("messages", "hi")], "task1")
+ saver.put(parent, empty_checkpoint(), {}, {})
+
+ result = saver.get_delta_channel_history(config=thread,
channels=["messages"])
+
+ assert result == {"messages": {"writes": [("task1", "messages",
"hi")]}}
+
class TestBaseFallbackGetChannelWrites:
"""Exercises the `BaseCheckpointSaver.get_delta_channel_history` default
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/tests/test_store.py
new/langgraph_checkpoint-4.3.0/tests/test_store.py
--- old/langgraph_checkpoint-4.2.0/tests/test_store.py 2020-02-02
01:00:00.000000000 +0100
+++ new/langgraph_checkpoint-4.3.0/tests/test_store.py 2020-02-02
01:00:00.000000000 +0100
@@ -1,7 +1,9 @@
import asyncio
import json
-from collections.abc import Iterable
+from collections import UserDict
+from collections.abc import Iterable, Mapping
from datetime import datetime
+from types import MappingProxyType
from typing import Any
import pytest
@@ -11,10 +13,14 @@
GetOp,
InvalidNamespaceError,
Item,
+ ListNamespacesOp,
+ MatchCondition,
Op,
PutOp,
Result,
+ SearchOp,
get_text_at_path,
+ validate_op_namespace,
)
from langgraph.store.base.batch import AsyncBatchedBaseStore
from langgraph.store.memory import InMemoryStore
@@ -137,6 +143,18 @@
assert get_text_at_path(nested_data, "nested[{invalid}]") == []
[email protected](
+ "mapping",
+ [
+ UserDict({"text": "searchable"}),
+ MappingProxyType({"text": "searchable"}),
+ ],
+)
+def test_get_text_at_path_with_non_dict_mapping(mapping: Mapping[str, str]) ->
None:
+ assert get_text_at_path(mapping, "$") == ['{"text": "searchable"}']
+ assert get_text_at_path(mapping, "text") == ["searchable"]
+
+
async def test_async_batch_store(mocker: MockerFixture) -> None:
abatch = mocker.stub()
@@ -514,6 +532,127 @@
assert (await async_store.aget(("valid", "namespace"), "key")) is None
+INVALID_NAMESPACES = [("foo.bar",), ("foo", ""), (123,)]
+NAMESPACE_METHODS = ["get", "delete", "search", "prefix", "suffix"]
+
+
[email protected]("namespace", INVALID_NAMESPACES)
[email protected]("method", NAMESPACE_METHODS)
+def test_rejects_invalid_namespace_labels(
+ mocker: MockerFixture, namespace: tuple, method: str
+) -> None:
+ store = InMemoryStore()
+ batch = mocker.spy(InMemoryStore, "batch")
+ call = {
+ "get": lambda: store.get(namespace, "key"),
+ "delete": lambda: store.delete(namespace, "key"),
+ "search": lambda: store.search(namespace),
+ "prefix": lambda: store.list_namespaces(prefix=namespace),
+ "suffix": lambda: store.list_namespaces(suffix=namespace),
+ }[method]
+
+ with pytest.raises(InvalidNamespaceError):
+ call()
+
+ batch.assert_not_called()
+
+
[email protected]("batched", [False, True])
[email protected]("namespace", INVALID_NAMESPACES)
[email protected]("method", NAMESPACE_METHODS)
+async def test_async_rejects_invalid_namespace_labels(
+ mocker: MockerFixture, batched: bool, namespace: tuple, method: str
+) -> None:
+ # The batched store must reject before queueing: a failure inside the
+ # shared `abatch` would fail every op queued alongside this one.
+ store = MockAsyncBatchedStore() if batched else InMemoryStore()
+ # `MockAsyncBatchedStore` dispatches through `InMemoryStore.batch`.
+ batch = mocker.spy(InMemoryStore, "batch")
+ abatch = mocker.spy(InMemoryStore, "abatch")
+ call = {
+ "get": lambda: store.aget(namespace, "key"),
+ "delete": lambda: store.adelete(namespace, "key"),
+ "search": lambda: store.asearch(namespace),
+ "prefix": lambda: store.alist_namespaces(prefix=namespace),
+ "suffix": lambda: store.alist_namespaces(suffix=namespace),
+ }[method]
+
+ with pytest.raises(InvalidNamespaceError):
+ await call()
+
+ batch.assert_not_called()
+ abatch.assert_not_called()
+
+
+def test_search_and_listing_keep_empty_prefixes_and_wildcards() -> None:
+ store = InMemoryStore()
+ store.put(("tenant", "a_%"), "key", {"v": 1})
+ store.put(("tenant", "b", "child"), "key", {"v": 1})
+
+ assert len(store.search(())) == 2
+ assert [item.namespace for item in store.search(("tenant", "a_%"))] == [
+ ("tenant", "a_%")
+ ]
+ assert sorted(store.list_namespaces(prefix=("tenant", "*"),
suffix=("*",))) == [
+ ("tenant", "a_%"),
+ ("tenant", "b", "child"),
+ ]
+
+
[email protected]("batched", [False, True])
+async def test_async_search_and_listing_keep_empty_prefixes_and_wildcards(
+ batched: bool,
+) -> None:
+ store = MockAsyncBatchedStore() if batched else InMemoryStore()
+ await store.aput(("tenant", "a_%"), "key", {"v": 1})
+ await store.aput(("tenant", "b", "child"), "key", {"v": 1})
+
+ assert len(await store.asearch(())) == 2
+ assert [item.namespace for item in await store.asearch(("tenant", "a_%"))]
== [
+ ("tenant", "a_%")
+ ]
+ assert sorted(
+ await store.alist_namespaces(prefix=("tenant", "*"), suffix=("*",))
+ ) == [("tenant", "a_%"), ("tenant", "b", "child")]
+
+
[email protected]("namespace", INVALID_NAMESPACES)
[email protected](
+ "kind", ["get", "put", "delete", "search", "list_prefix", "list_suffix"]
+)
+def test_validate_op_namespace_rejects_invalid_labels(
+ namespace: tuple, kind: str
+) -> None:
+ op = {
+ "get": GetOp(namespace, "key"),
+ "put": PutOp(namespace, "key", {"v": 1}),
+ "delete": PutOp(namespace, "key", None),
+ "search": SearchOp(namespace),
+ "list_prefix": ListNamespacesOp((MatchCondition("prefix",
namespace),)),
+ "list_suffix": ListNamespacesOp((MatchCondition("suffix",
namespace),)),
+ }[kind]
+
+ with pytest.raises(InvalidNamespaceError):
+ validate_op_namespace(op)
+
+
+def test_validate_op_namespace_allows_empty_prefix_and_wildcards() -> None:
+ for op in (
+ SearchOp(()),
+ ListNamespacesOp(),
+ ListNamespacesOp(
+ (
+ MatchCondition("prefix", ("tenant", "*")),
+ MatchCondition("suffix", ("*",)),
+ )
+ ),
+ GetOp(("tenant", "a_%"), "key"),
+ # Write-only rules belong to `put`, not to op validation.
+ PutOp(("langgraph", "x"), "key", {"v": 1}),
+ ):
+ validate_op_namespace(op)
+
+
async def test_async_batch_store_deduplication(mocker: MockerFixture) -> None:
abatch = mocker.spy(InMemoryStore, "batch")
store = MockAsyncBatchedStore()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/langgraph_checkpoint-4.2.0/uv.lock
new/langgraph_checkpoint-4.3.0/uv.lock
--- old/langgraph_checkpoint-4.2.0/uv.lock 2020-02-02 01:00:00.000000000
+0100
+++ new/langgraph_checkpoint-4.3.0/uv.lock 2020-02-02 01:00:00.000000000
+0100
@@ -19,16 +19,16 @@
[[package]]
name = "anyio"
-version = "4.12.1"
+version = "4.14.2"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
{ name = "idna" },
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/96/f0/5eb65b2bb0d09ac6776f2eb54adee6abe8228ea05b20a5ad0e4945de8aac/anyio-4.12.1.tar.gz",
hash =
"sha256:41cfcc3a4c85d3f05c932da7c26d0201ac36f72abd4435ba90d0464a3ffed703", size
= 228685, upload-time = "2026-01-06T11:45:21.246Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/61/cc/a381afa6efea9f496eff839d4a6a1aed3bfafc7b3ab4b0d1b243a12573dd/anyio-4.14.2.tar.gz",
hash =
"sha256:cfa139f3ed1a23ee8f88a145ddb5ac7605b8bbfd8592baacd7ce3d8bb4313c7f", size
= 260176, upload-time = "2026-07-12T20:29:07.082Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/38/0e/27be9fdef66e72d64c0cdc3cc2823101b80585f8119b5c112c2e8f5f7dab/anyio-4.12.1-py3-none-any.whl",
hash =
"sha256:d405828884fc140aa80a3c667b8beed277f1dfedec42ba031bd6ac3db606ab6c", size
= 113592, upload-time = "2026-01-06T11:45:19.497Z" },
+ { url =
"https://files.pythonhosted.org/packages/da/35/f2287558c17e29fafc8ef3daf819bb9834061cfa43bff8014f7df7f63bdc/anyio-4.14.2-py3-none-any.whl",
hash =
"sha256:9f505dda5ac9f0c8309b5e8bd445a8c2bf7246f3ce950121e45ea15bc41d1494", size
= 125813, upload-time = "2026-07-12T20:29:05.763Z" },
]
[[package]]
@@ -183,7 +183,7 @@
version = "1.3.1"
source = { registry = "https://pypi.org/simple" }
dependencies = [
- { name = "typing-extensions", marker = "python_full_version < '3.11'" },
+ { name = "typing-extensions" },
]
sdist = { url =
"https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz",
hash =
"sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size
= 30371, upload-time = "2025-11-21T23:01:54.787Z" }
wheels = [
@@ -268,9 +268,10 @@
[[package]]
name = "langchain-core"
-version = "1.5.2"
+version = "1.6.5"
source = { registry = "https://pypi.org/simple" }
dependencies = [
+ { name = "httpx" },
{ name = "jsonpatch" },
{ name = "langchain-protocol" },
{ name = "langsmith" },
@@ -281,9 +282,9 @@
{ name = "typing-extensions" },
{ name = "uuid-utils" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/6e/58/3ad53096eee1e07728e8219ded30ae308b0f2b8b7b26b8ebb6371917c0f5/langchain_core-1.5.2.tar.gz",
hash =
"sha256:2d13ab35b42eec63d4669a483776b8cdd778ee764107149369fb369d84c08c41", size
= 972322, upload-time = "2026-07-28T16:38:37.977Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/ed/ed/ceecd3bfcfc77a94cf30a9f1506e907fdea447458825e01914a72d2d1a6f/langchain_core-1.6.5.tar.gz",
hash =
"sha256:bdb059fef65473fd444558dbb18f50901657402c43ceed9dc0fdc7b76a393c6b", size
= 1007041, upload-time = "2026-09-24T18:11:06.487Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/ca/e4/024e402a65f5ee2eb6ae9667b5ffc5f08776cb4e712f5a11ee1997d56083/langchain_core-1.5.2-py3-none-any.whl",
hash =
"sha256:a687dd7c3b22c6c1294e1c1eeb61fb6f3a308e6015a1d75b576b3836ad5b5aed", size
= 561643, upload-time = "2026-07-28T16:38:36.38Z" },
+ { url =
"https://files.pythonhosted.org/packages/59/68/447ac7e734990b7ed9dcfc3b6dee9a4cd4d4169e296429fa71a9a47c1c7b/langchain_core-1.6.5-py3-none-any.whl",
hash =
"sha256:54c7b0e9314b9084fb04405bb33dc5d32986d512d92b7b8863899cd5f6267556", size
= 572136, upload-time = "2026-09-24T18:11:04.837Z" },
]
[[package]]
@@ -300,7 +301,7 @@
[[package]]
name = "langgraph-checkpoint"
-version = "4.2.0"
+version = "4.3.0"
source = { editable = "." }
dependencies = [
{ name = "langchain-core" },
@@ -1014,14 +1015,14 @@
[[package]]
name = "pytest-mock"
-version = "3.15.1"
+version = "3.16.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "pytest" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/68/14/eb014d26be205d38ad5ad20d9a80f7d201472e08167f0bb4361e251084a9/pytest_mock-3.15.1.tar.gz",
hash =
"sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f", size
= 34036, upload-time = "2025-09-16T16:37:27.081Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/7a/7f/6ed29931d5c8cd396e7c0a55412e6cc88020373365c8685985dea53d26d7/pytest_mock-3.16.0.tar.gz",
hash =
"sha256:5a8395528b8f498205f3718f575228d0edaed7425fff638f87d1a6c3e0383636", size
= 35362, upload-time = "2026-09-27T14:57:55.46Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/5a/cc/06253936f4a7fa2e0f48dfe6d851d9c56df896a9ab09ac019d70b760619c/pytest_mock-3.15.1-py3-none-any.whl",
hash =
"sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d", size
= 10095, upload-time = "2025-09-16T16:37:25.734Z" },
+ { url =
"https://files.pythonhosted.org/packages/db/5b/b83a9bf1a3b4ec222f9fa083147ff6816245223da0ab92370e7e056f113f/pytest_mock-3.16.0-py3-none-any.whl",
hash =
"sha256:007cfeb257801d88d9c0b2a7b5a15a15e73b71968dfd72e7bf8c4a2f8393aec8", size
= 10016, upload-time = "2026-09-27T14:57:54.283Z" },
]
[[package]]
@@ -1124,14 +1125,14 @@
[[package]]
name = "redis"
-version = "8.0.1"
+version = "8.1.0"
source = { registry = "https://pypi.org/simple" }
dependencies = [
{ name = "async-timeout", marker = "python_full_version < '3.11.3'" },
]
-sdist = { url =
"https://files.pythonhosted.org/packages/cc/c3/928b290c2c0ca99ab96eea5b4ff8f30be8112b075301a7d3ba214a3c8c12/redis-8.0.1.tar.gz",
hash =
"sha256:afc5a7a2f5a084f5b1880dec548dd45be17db7e43c82a30d84f952aefb05cfb0", size
= 5114170, upload-time = "2026-06-23T14:52:37.728Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/a8/99/604f0b666d4c616d891cf77ebb9db6bb21601344c051aebf1b72b9ff915f/redis-8.1.0.tar.gz",
hash =
"sha256:6e1a19beef9225c83efd689c7e6b7da2d5215b1f42cd13b7fc3714d0a09c7b25", size
= 5254356, upload-time = "2026-07-30T08:51:00.269Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/fd/0a/c2345ebf1ebe70840ce3f6c6ee612f8fa749cfbd1b03069c53bf0c62aaad/redis-8.0.1-py3-none-any.whl",
hash =
"sha256:47daa35a058c23468d6437f17a8c76882cb316b838ef763036af99b96cedd743", size
= 502406, upload-time = "2026-06-23T14:52:36.137Z" },
+ { url =
"https://files.pythonhosted.org/packages/66/9d/c5731f6e3608663d4d3656fd8d3aecee8b509c3082818f5a13eae925baea/redis-8.1.0-py3-none-any.whl",
hash =
"sha256:a4fe1aac3d3b3cc791d4b3d5931c5a956045dc951ee74d1c913ee3ac4d2ee9fb", size
= 560618, upload-time = "2026-07-30T08:50:58.497Z" },
]
[[package]]
@@ -1163,27 +1164,27 @@
[[package]]
name = "ruff"
-version = "0.16.0"
+version = "0.16.9"
source = { registry = "https://pypi.org/simple" }
-sdist = { url =
"https://files.pythonhosted.org/packages/4d/94/1e5e4967626faf12fa56999cd6222dff6992ceb086ad7945756baf70c7a7/ruff-0.16.0.tar.gz",
hash =
"sha256:e460aafd5495ec89efaa6ced2e4a9a581116451e1c88b9d37ef497e0f8e93982", size
= 4790557, upload-time = "2026-07-23T19:11:30.981Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/96/bf/c935ca98e73fe8ce65b87ef08a280c0c1e85295d569228c15e87d8fdfaf1/ruff-0.16.9.tar.gz",
hash =
"sha256:12b625c6cfba78d285d9f48eda5f053374f1e53cb10ef17342a383750db99161", size
= 4948764, upload-time = "2026-09-24T20:37:49.416Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/4b/81/1c8818fee7ce1a04cd7d1b3172e0a8f8e4f1dc4feb7fc390e16daa8af323/ruff-0.16.0-py3-none-linux_armv6l.whl",
hash =
"sha256:e5115729eb08c585e5121978ba5d5b60caeae394ce21b9fb5e6cd33a1c6c9b1e", size
= 10754633, upload-time = "2026-07-23T19:10:46.415Z" },
- { url =
"https://files.pythonhosted.org/packages/23/df/beaf59c09d68db84304d555f188b276a77132a5d5b0b67a5c762aa143628/ruff-0.16.0-py3-none-macosx_10_12_x86_64.whl",
hash =
"sha256:3c954b1d580bfa035b41654f7858cc7e71d5fc3ac5b723dd62bd9133830ed522", size
= 10969164, upload-time = "2026-07-23T19:10:50.271Z" },
- { url =
"https://files.pythonhosted.org/packages/42/ce/741cd197496a1abbf51352710fd15ed995d2a2be87189c1da26a450d6e83/ruff-0.16.0-py3-none-macosx_11_0_arm64.whl",
hash =
"sha256:e01c21d10eb1b29f47b7454e1f4056db9a3f0260c646aa88457c610291db9f81", size
= 10488846, upload-time = "2026-07-23T19:10:52.639Z" },
- { url =
"https://files.pythonhosted.org/packages/52/2a/a2db8e88cade358f5cdcb05674a917751074109315d014eb6352d9a893f7/ruff-0.16.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:6e364e5ed22ed8dc05082fd78e35308618260907ac2d3c1d637b2e682415b6c9", size
= 10889729, upload-time = "2026-07-23T19:10:54.89Z" },
- { url =
"https://files.pythonhosted.org/packages/42/65/62a771694ebd63029dc953e27dbad40e1588bd4860ff9fe881018fddaa49/ruff-0.16.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:d327b8fc113a1d4421a04f3839d3752057c8dd1ee320223a6f3f52d04ada462a", size
= 10568275, upload-time = "2026-07-23T19:10:56.993Z" },
- { url =
"https://files.pythonhosted.org/packages/3f/e2/ced249fe8af5f086c5c58cc21cc3356d50f32f7401c5df87050c999620a7/ruff-0.16.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:a9b50c55e263103586b3dcf5f73d479eb8cb5fdb6098fec59a62891dab653717", size
= 11385112, upload-time = "2026-07-23T19:10:59.615Z" },
- { url =
"https://files.pythonhosted.org/packages/87/0b/05154977a8fd69eeb6c103271f55403bfd8711f5c0f8ed07489d95a504e7/ruff-0.16.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:0ff4a79ce3ec0172f3241943835de1c4cb4e2dcd07f0f8c2d02603dbbbee4b17", size
= 12207008, upload-time = "2026-07-23T19:11:02.154Z" },
- { url =
"https://files.pythonhosted.org/packages/fb/29/98225831a3a1eab0e02f4acc6ca6559a98611dcc68b6965ff4b7234627c1/ruff-0.16.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:e95c448fca1fb2a18372a9440926c5a6ee789639bb975c72e7ae6d0b04218ab4", size
= 11650842, upload-time = "2026-07-23T19:11:04.557Z" },
- { url =
"https://files.pythonhosted.org/packages/91/66/6bd3cf90500653d55dc0ffc8507aa8300bd49d0214b2e8cb4d3fef2943ba/ruff-0.16.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:4f11a8d11010301d0a398a2fdef67691feca7294da6aef55e2150e8fa2cd520b", size
= 11400718, upload-time = "2026-07-23T19:11:09.233Z" },
- { url =
"https://files.pythonhosted.org/packages/8e/a2/a54eb4eae05d66364050a5d3b8a9c5ef88196531b3cbe7109d873f87f819/ruff-0.16.0-py3-none-manylinux_2_31_riscv64.whl",
hash =
"sha256:48044c678e9cb8698246c99b14aaccfa6601dea7379eb48a6f8f73f7a6d86cd0", size
= 11426177, upload-time = "2026-07-23T19:11:11.994Z" },
- { url =
"https://files.pythonhosted.org/packages/1a/be/16e3eea4b2a478a496919f5e36f17c4559e54620bd3bbac5d6affa068006/ruff-0.16.0-py3-none-musllinux_1_2_aarch64.whl",
hash =
"sha256:7aa0959bad8eb8bef50340154fc9b58678dae31fa4293afa38b44b6e552c0213", size
= 10856126, upload-time = "2026-07-23T19:11:14.221Z" },
- { url =
"https://files.pythonhosted.org/packages/a2/84/252eb8b868a16eec7257c14f504f77537e734b2d69c762e639e588e304a3/ruff-0.16.0-py3-none-musllinux_1_2_armv7l.whl",
hash =
"sha256:28ea2b7df8ebf7f9da6b7d47b230ab48f387c0a29be3b474c4d0740e197bb9af", size
= 10571208, upload-time = "2026-07-23T19:11:16.378Z" },
- { url =
"https://files.pythonhosted.org/packages/21/09/817a482f542f7570cbb4554b26e896610c7114f539b1d9e2d2145bf6bef6/ruff-0.16.0-py3-none-musllinux_1_2_i686.whl",
hash =
"sha256:33a3dfac8c35f81498dea9181bccc2f4c4bc8f1521a1dd9406e77643e0f0fb09", size
= 11063329, upload-time = "2026-07-23T19:11:19.173Z" },
- { url =
"https://files.pythonhosted.org/packages/2e/23/9403c180ca1cb9b1f7335f5c3e5305c09d49ea5b345196682a36028bde4a/ruff-0.16.0-py3-none-musllinux_1_2_x86_64.whl",
hash =
"sha256:a5237a0bda500d30d81b8e07a6973a5cbc772864cbf746ae2f4e8a2e01c9f4ed", size
= 11489751, upload-time = "2026-07-23T19:11:21.74Z" },
- { url =
"https://files.pythonhosted.org/packages/b2/1d/1b2ef7bcde851c78d7f17f1cca13fd6dc695fc4b3d6197941e72cae5b132/ruff-0.16.0-py3-none-win32.whl",
hash =
"sha256:7fab76fa065c873f41ff744347c6e77bcc3dfec4bcc754dc26b63d23c0f7f5fb", size
= 10785885, upload-time = "2026-07-23T19:11:23.947Z" },
- { url =
"https://files.pythonhosted.org/packages/b2/a3/d5e4ef7a56be3f928ffb90b94c25ba7d3cb9c7fe0736aeaaedf361770712/ruff-0.16.0-py3-none-win_amd64.whl",
hash =
"sha256:429c117f022bf481fabd9d551e7a3952b24c65e6ef44337ea09d90bebef14472", size
= 11923141, upload-time = "2026-07-23T19:11:26.409Z" },
- { url =
"https://files.pythonhosted.org/packages/cb/9a/8415f2657cbe200f41a4531ccededf135505a92d4a012229121f885b26f9/ruff-0.16.0-py3-none-win_arm64.whl",
hash =
"sha256:14296fedcd2705c77ab8235439278bbb38f285cf7da5528b00b3e330c3d4872d", size
= 11273407, upload-time = "2026-07-23T19:11:28.705Z" },
+ { url =
"https://files.pythonhosted.org/packages/0d/26/df51322b52ee1ada7eff2d071ea09d11d5c2d1dcc9f02594f5785c4d1635/ruff-0.16.9-py3-none-linux_armv6l.whl",
hash =
"sha256:95e6f022090368ab3b824c36276839c53b2adf1a3f4c09fefc33dfc400f6da96", size
= 10082922, upload-time = "2026-09-24T20:37:13.045Z" },
+ { url =
"https://files.pythonhosted.org/packages/a5/27/7bf51f5a7aa375e9f339280a303aab44ca75dc1525f1cdc5991761685b0f/ruff-0.16.9-py3-none-macosx_10_12_x86_64.whl",
hash =
"sha256:a5f27be168556594a86d2f415db0cf43f5291917849318f873c7e2791f7a8c67", size
= 10236360, upload-time = "2026-09-24T20:37:16.049Z" },
+ { url =
"https://files.pythonhosted.org/packages/b6/63/09659283f92f02dff45809da194a70da2f688d87c55d8875c4fae3536072/ruff-0.16.9-py3-none-macosx_11_0_arm64.whl",
hash =
"sha256:1632eb1d6197f33bd00b1acbc5b71009e89a8895c158e2d2b03a834fac964ab6", size
= 9892940, upload-time = "2026-09-24T20:37:17.957Z" },
+ { url =
"https://files.pythonhosted.org/packages/24/58/98de1b72ec172f5f8f1731236fe21585b3998bf7dfe9fcc44ae9ba626012/ruff-0.16.9-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:b3f951b14d865d5952c89d40a5ca07e87abe24fa5453299878411e127748fb1c", size
= 10032114, upload-time = "2026-09-24T20:37:19.942Z" },
+ { url =
"https://files.pythonhosted.org/packages/c8/7d/f1e17c54ab59d4bad1dce8ee3e22a7a1d0ef4745240decacdcf3832b5bb2/ruff-0.16.9-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:447fc07e1573afff7cb02803462b12b6c8ece7cf10e2cd78565fa6d7a1c0bf8d", size
= 9910227, upload-time = "2026-09-24T20:37:21.872Z" },
+ { url =
"https://files.pythonhosted.org/packages/34/19/436f647a65075bbd3bab2668b3bdaa5120559b294694018cdcefabbbf30b/ruff-0.16.9-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:8a3e039a6a40ed976c491722b60e0ae4a4aa1a86057f540ee7a37a5d19ae9120", size
= 10547484, upload-time = "2026-09-24T20:37:24.229Z" },
+ { url =
"https://files.pythonhosted.org/packages/03/59/38430a6bc2f6d8095447ac39625cf8b6e9344a47e6c26225c8ba1bff3ffb/ruff-0.16.9-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:4684dded7db60aa57cb118fa158630f5feade4af5782903b6053484bdf9bd129", size
= 11412367, upload-time = "2026-09-24T20:37:26.307Z" },
+ { url =
"https://files.pythonhosted.org/packages/c8/bd/bbb6d7fc7f208c8b8c50dd5dc8206e4cfdb1e7a8fb852606a3adf370c880/ruff-0.16.9-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:d29c934357e45642fda2f34c0b1f4025b4a6c01e15e4bf0016879d60078a142c", size
= 10869787, upload-time = "2026-09-24T20:37:28.35Z" },
+ { url =
"https://files.pythonhosted.org/packages/bc/b8/9c543074918061abbefc3bd139bee22de35abedb00dde0f2d27288838962/ruff-0.16.9-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:a21713e629d3e5bdb2f5c2def1cc7f04f47fa8e1a7eb0571b4a28e1da64bc728", size
= 10406494, upload-time = "2026-09-24T20:37:30.624Z" },
+ { url =
"https://files.pythonhosted.org/packages/35/7a/5a8851bd146e7ccf8fd4b003f6c75c11f8fbdb0e60673b45097986b6bf41/ruff-0.16.9-py3-none-manylinux_2_31_riscv64.whl",
hash =
"sha256:7baa24ef5fc8e77aa93879e1d3f43754a01ae488e869f1ae30cf431afd4d2452", size
= 10590083, upload-time = "2026-09-24T20:37:32.439Z" },
+ { url =
"https://files.pythonhosted.org/packages/87/f0/4c3467188f23f806960b46fa76575a7cd0514c9ba90562650b71efc96980/ruff-0.16.9-py3-none-musllinux_1_2_aarch64.whl",
hash =
"sha256:a41aac6230aadfaa133bdfa1614488531ffa3e0837567ae04c0da2058a9c0f9e", size
= 10119151, upload-time = "2026-09-24T20:37:34.581Z" },
+ { url =
"https://files.pythonhosted.org/packages/15/34/5a4def5adea572ce6aea0bb64f21f928ee317b80e0db747d7979b01d7261/ruff-0.16.9-py3-none-musllinux_1_2_armv7l.whl",
hash =
"sha256:c2529fb5896d49115b0e9aa8f887490b34bbe76baf879ec2264ac59406869ce7", size
= 9911544, upload-time = "2026-09-24T20:37:36.796Z" },
+ { url =
"https://files.pythonhosted.org/packages/62/5d/d15ebea7499eef9373318c0ee6ca127832927c6529731f6d48e18dce7ca9/ruff-0.16.9-py3-none-musllinux_1_2_i686.whl",
hash =
"sha256:41e3870277694177429b56406d65dfbdb2c2802c52b715edaf6a0b829c69d4ee", size
= 10269884, upload-time = "2026-09-24T20:37:38.857Z" },
+ { url =
"https://files.pythonhosted.org/packages/d1/56/c5d3cd119ded7a3c7aba0e961b69cb3df701c91662c98ad694467d060ce1/ruff-0.16.9-py3-none-musllinux_1_2_x86_64.whl",
hash =
"sha256:8adbe4e58af167f767d7b2ba5e83c42e878350796cf78c2f5e14ab9903a92588", size
= 10749366, upload-time = "2026-09-24T20:37:41.042Z" },
+ { url =
"https://files.pythonhosted.org/packages/ac/fe/734ec7527029ac757ecf821f143c9f3fcf69149c21f53a044a899b430f5a/ruff-0.16.9-py3-none-win32.whl",
hash =
"sha256:0e1dbc2073624dee6618d41d0098690a7244654af746704b64759e12b6b6b385", size
= 10152355, upload-time = "2026-09-24T20:37:43.025Z" },
+ { url =
"https://files.pythonhosted.org/packages/14/21/26e4643629b3ebb44f0a06f9c9a53058d63d989415f63a9a3c28e2ee7f22/ruff-0.16.9-py3-none-win_amd64.whl",
hash =
"sha256:6bd40fec8cd4c8a3d4dd589bd8ad4e6320c13c29234159bfd959a40d529d597b", size
= 10592965, upload-time = "2026-09-24T20:37:44.944Z" },
+ { url =
"https://files.pythonhosted.org/packages/51/60/5fb1a39dbb5ae314d5f59bc7348a63c1d5c20f3cd83914c4b5cb0be31d2d/ruff-0.16.9-py3-none-win_arm64.whl",
hash =
"sha256:ed1a252039200f57a59eebc063b54beabea67bfbaaca0eeaa7f54b5fbcda2284", size
= 10458649, upload-time = "2026-09-24T20:37:46.882Z" },
]
[[package]]
@@ -1260,27 +1261,27 @@
[[package]]
name = "ty"
-version = "0.0.64"
+version = "0.0.84"
source = { registry = "https://pypi.org/simple" }
-sdist = { url =
"https://files.pythonhosted.org/packages/8e/aa/14c9965d3b173105692473897cc89c34cd91241368b2044e43167e1c17ff/ty-0.0.64.tar.gz",
hash =
"sha256:d12ddbb05f15158bb518af619378b385486450def95fb06f8ab98037febe9f2c", size
= 6350966, upload-time = "2026-07-27T18:32:45.403Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/e1/f6/34f8869c45ea87fe6a931ffa824b1fe4428167173543d92988d631add355/ty-0.0.84.tar.gz",
hash =
"sha256:0cefdb0cd5d399418dbe83c349ba605047b7dff815ae6f460c80e8522b40be67", size
= 7409537, upload-time = "2026-09-24T13:16:24.367Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/ae/4c/c54937e4ff3fa7b34a99ea3387ec766bf0ad98dc8df8d792e89b388e658e/ty-0.0.64-py3-none-linux_armv6l.whl",
hash =
"sha256:3830a6675ab43635ced1c4c557f380ac4a49e9414e03975e4e4e8db644c64944", size
= 12118357, upload-time = "2026-07-27T18:32:08.702Z" },
- { url =
"https://files.pythonhosted.org/packages/ce/aa/a839ee2bc78e943d079e6abe199a97b4eeffb7e5c9a57326d69de452186a/ty-0.0.64-py3-none-macosx_10_12_x86_64.whl",
hash =
"sha256:3ff07d7bc32a2135f58afe57393789a32ea2fed1a66216129a8e535e76043903", size
= 11790882, upload-time = "2026-07-27T18:32:10.997Z" },
- { url =
"https://files.pythonhosted.org/packages/4c/de/19f14357888a7198438926303753cf749428e3d62e8980ff1e9a72a78402/ty-0.0.64-py3-none-macosx_11_0_arm64.whl",
hash =
"sha256:4f6d1c7f897cca05d12bacbf1435150d5ffa496099515aa6ed303c8b29e1d0bb", size
= 11317394, upload-time = "2026-07-27T18:32:13.162Z" },
- { url =
"https://files.pythonhosted.org/packages/08/2f/f54462300535ab99b551eda733177be2eef5dbc2997d3fdb357c4ddd760a/ty-0.0.64-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:138d6c37ad4bf8583aa7a9b29d90954151d7856f9910a03eae3eb34b34c57215", size
= 11863042, upload-time = "2026-07-27T18:32:15.307Z" },
- { url =
"https://files.pythonhosted.org/packages/5e/95/dbecf745520ebe8bd7b02fc55eee6441c9be312ebf6addce605eb52740dd/ty-0.0.64-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:1ed9719d1b7b66fb8efe073d860208a44c40af1f6cd5c2364aa9b323a1e579b4", size
= 11910730, upload-time = "2026-07-27T18:32:17.467Z" },
- { url =
"https://files.pythonhosted.org/packages/3b/26/12cfd40028e51ceed7b3cb645281c61c02eb64ff9fb0c09231d65c30ff25/ty-0.0.64-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:d68b23e5169e2137b5f1de7169ab0cebecab6c8eda374c34c1f6394308f58242", size
= 12631936, upload-time = "2026-07-27T18:32:19.533Z" },
- { url =
"https://files.pythonhosted.org/packages/a0/d0/65ffc2b0a686347193c6f98e9421a7fc2a96fc3cd0b1001cf7cf284baff9/ty-0.0.64-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:f41cb07d89d32626fcaf3ed4d262778fcb28b2628b6ed1e172cd7b18820668d8", size
= 13171049, upload-time = "2026-07-27T18:32:22.026Z" },
- { url =
"https://files.pythonhosted.org/packages/f6/a4/975a5961842dcd6fa60f0770a102c0bba7509da909ab652919bfcdcd4fc7/ty-0.0.64-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:5f24e1504ab9e212f92356b82fe088fdeb3a39f9a2f4ff25e505d2e1d0db9056", size
= 12826438, upload-time = "2026-07-27T18:32:24.178Z" },
- { url =
"https://files.pythonhosted.org/packages/af/ef/dfb9b7f9bcc032d3b540b0d1f55f532a336e2fb41b1bd539c05ae81a151a/ty-0.0.64-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:86db830cb914bb33bb8247b66ccea58de4496c2391bd42658aba744b439f3290", size
= 12440880, upload-time = "2026-07-27T18:32:26.341Z" },
- { url =
"https://files.pythonhosted.org/packages/ee/d0/bedac20505e8a8f5501ad73d7d15d8e421a563fef59993909a23036929a4/ty-0.0.64-py3-none-manylinux_2_31_riscv64.whl",
hash =
"sha256:652ee3d6d03bea76cd2fe8949c78bb5970394ebd7c5fd270e9518c0dee1b931d", size
= 12782439, upload-time = "2026-07-27T18:32:28.642Z" },
- { url =
"https://files.pythonhosted.org/packages/79/d5/795733f13ceff1378f08b3de0c49d0f518df220ed856b0dfac869f3b7c81/ty-0.0.64-py3-none-musllinux_1_2_aarch64.whl",
hash =
"sha256:4838768295774a86e95f9ec5633e739d016adbbb69dcbdc62f3549578a11f624", size
= 11814821, upload-time = "2026-07-27T18:32:30.632Z" },
- { url =
"https://files.pythonhosted.org/packages/52/3e/9d99cd1e1831003434f508ed9f258a56543194afc3bbe051eba2545fa676/ty-0.0.64-py3-none-musllinux_1_2_armv7l.whl",
hash =
"sha256:5a3d700669868599edf39ce5125196682f15a8880cc8c669bc2a83b99984d99b", size
= 11928678, upload-time = "2026-07-27T18:32:32.888Z" },
- { url =
"https://files.pythonhosted.org/packages/b8/3d/448f49a3503fb119a34348a5714bb92001f252fadbbb12d645f2e744b557/ty-0.0.64-py3-none-musllinux_1_2_i686.whl",
hash =
"sha256:b161f0a82a8e2f2432db3bf7702b4d3924fa9486ba0014f6710a160fc157df0d", size
= 12202249, upload-time = "2026-07-27T18:32:34.905Z" },
- { url =
"https://files.pythonhosted.org/packages/dd/9b/75768e562cec990d189dc05807ae72890b20ffbd1e1f43597bb98db63c60/ty-0.0.64-py3-none-musllinux_1_2_x86_64.whl",
hash =
"sha256:39b9dd42908df47c2dc57dda87e656fab97097ffd2618474bbdea986af0d6a9d", size
= 12548817, upload-time = "2026-07-27T18:32:36.995Z" },
- { url =
"https://files.pythonhosted.org/packages/34/89/44cc276ea6ca0245495014758ffeadde1798fb0b5840c9cf36d8d2ed3250/ty-0.0.64-py3-none-win32.whl",
hash =
"sha256:d0676ab0e0935795e5843baa28dd5e366dc343d7c0945a996df9eab8e0644885", size
= 11545474, upload-time = "2026-07-27T18:32:39.389Z" },
- { url =
"https://files.pythonhosted.org/packages/01/7e/d1c8a871a38d17c8f168b9a6975f6247f7660f8334e517656a5e4b4a4858/ty-0.0.64-py3-none-win_amd64.whl",
hash =
"sha256:dcb9bd31f54097e362b776c26ab4564d4564cdd1355cb883481167a26c03cc3f", size
= 12542987, upload-time = "2026-07-27T18:32:41.412Z" },
- { url =
"https://files.pythonhosted.org/packages/35/4d/6d18640d0204cacd69abbaca95ad6a34c6d7e9169e9051d0117b17b827ec/ty-0.0.64-py3-none-win_arm64.whl",
hash =
"sha256:82cc34c1ad9a8feb6059aef193bebcecc656e548f6fab3d518bcd8b57d198d39", size
= 11899263, upload-time = "2026-07-27T18:32:43.366Z" },
+ { url =
"https://files.pythonhosted.org/packages/aa/0c/600648778e1c79133ce6b6a5c4c2531ae16b90c9b30f5041b38b574f61b8/ty-0.0.84-py3-none-linux_armv6l.whl",
hash =
"sha256:868438e2b9abfc835dd5b5b07ed693db95d8348ac40e3228252511d63ae87695", size
= 13935333, upload-time = "2026-09-24T13:15:31.167Z" },
+ { url =
"https://files.pythonhosted.org/packages/c5/3b/27f06f49945c36170765fad82076898039ae3873338e9865f876dd62f12c/ty-0.0.84-py3-none-macosx_10_12_x86_64.whl",
hash =
"sha256:b00f39b521f0b559cde0f6abf8dd47213b513b04f33d58efeb9b98486a16bb17", size
= 13511328, upload-time = "2026-09-24T13:15:34.446Z" },
+ { url =
"https://files.pythonhosted.org/packages/fc/b6/b12dd130e7f30141f0645614f454c925991cd389b1cc6c8284fd6bf32326/ty-0.0.84-py3-none-macosx_11_0_arm64.whl",
hash =
"sha256:8f78c2915567f2ee62ce0c24d86091bc76f81577677755e242d09951db588b9a", size
= 13445445, upload-time = "2026-09-24T13:15:37.476Z" },
+ { url =
"https://files.pythonhosted.org/packages/44/96/f012de4b3c1d9a4773326621380d768b4d48c47e620dc012775c5e01c7d7/ty-0.0.84-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl",
hash =
"sha256:61155cad0921e890d86d1d911a40b3a0e924ef4bdc3b4f3865a6c89c7e3012dc", size
= 13471235, upload-time = "2026-09-24T13:15:40.64Z" },
+ { url =
"https://files.pythonhosted.org/packages/05/32/dca630f5f5353fa7bf67eebccf1549df99b16656d21071d0df6677c826a5/ty-0.0.84-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl",
hash =
"sha256:417c3bf14947ed16b0b92976ab333c27915590354e96d4f581709068d3811355", size
= 13680704, upload-time = "2026-09-24T13:15:43.817Z" },
+ { url =
"https://files.pythonhosted.org/packages/44/8d/33702c8f62f05ad45b33644fb914d483de6a0a7bc8e51884e9b8773e6d69/ty-0.0.84-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl",
hash =
"sha256:e06ef117759f654f5379efe9ae79bda8a186016c016f1023d05c34f8e15c1546", size
= 14518923, upload-time = "2026-09-24T13:15:46.802Z" },
+ { url =
"https://files.pythonhosted.org/packages/c8/a1/da3246e6ef2ae0e842bca4058b25c54bee55ab058ffff4ee54e72517ec01/ty-0.0.84-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl",
hash =
"sha256:a05d1d53db8b64410ab38c6e32c5898510584869d1d5dd9c0605db81c9aef7df", size
= 15027731, upload-time = "2026-09-24T13:15:49.755Z" },
+ { url =
"https://files.pythonhosted.org/packages/20/17/b0099098a560aeb4f9fde6c912f9a81622c3e44e6555e1fbe322b368ec31/ty-0.0.84-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl",
hash =
"sha256:b92400494ab855cfb1204ac1101e3f53b2d09a8e21d171758b2cf9acdab1809e", size
= 14748260, upload-time = "2026-09-24T13:15:52.713Z" },
+ { url =
"https://files.pythonhosted.org/packages/60/d5/32cd67aedb271f006e716ad093806c96c5d7e2af86be8255469dbd3d76c8/ty-0.0.84-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
hash =
"sha256:af17eb391ae3027fed9be1780bea555c2b8a25ba68e184c627b4981b2c9eaab7", size
= 14205858, upload-time = "2026-09-24T13:15:55.677Z" },
+ { url =
"https://files.pythonhosted.org/packages/43/c4/638ac62ca2e8eca1b92e3e16273085744fada728b993500819b5c258ca15/ty-0.0.84-py3-none-manylinux_2_31_riscv64.whl",
hash =
"sha256:44cf06af0e7ec78ea6d8ff33a3450fc19627756a4fba681f7410d4e3ef63047a", size
= 14573196, upload-time = "2026-09-24T13:15:59.165Z" },
+ { url =
"https://files.pythonhosted.org/packages/a6/f6/9ee81c5d8921e5fd5f10889ae563c95cd3272b31df2ada528919ca1cef6b/ty-0.0.84-py3-none-musllinux_1_2_aarch64.whl",
hash =
"sha256:c6e56b443ff9ba462e34bfbc1e582004c2719ed35f8f93a433744b0ba0afb2d9", size
= 13480760, upload-time = "2026-09-24T13:16:02.313Z" },
+ { url =
"https://files.pythonhosted.org/packages/f6/83/fbe5d1177667ae16d84c3242846b143809c9cc09568b333e5a9b4d5908f6/ty-0.0.84-py3-none-musllinux_1_2_armv7l.whl",
hash =
"sha256:8b6562fcc48820c1030e2a4509ef2c14ef93043ca4860280074314ac3a825b95", size
= 13696346, upload-time = "2026-09-24T13:16:05.391Z" },
+ { url =
"https://files.pythonhosted.org/packages/86/9a/1b4ac9ddc34cc0ab4624bc219825d66af52f1ad87f4778ad08ad03fa06d5/ty-0.0.84-py3-none-musllinux_1_2_i686.whl",
hash =
"sha256:dee7421451efcbd70f03e95a8f2c8d9e5ec3d35edcd27b4095ee00ee062abfc4", size
= 13959410, upload-time = "2026-09-24T13:16:08.661Z" },
+ { url =
"https://files.pythonhosted.org/packages/c9/04/70e289437a67dfd686056ab4fd91880261a8233033a6a95d29393741fb97/ty-0.0.84-py3-none-musllinux_1_2_x86_64.whl",
hash =
"sha256:31e96307cf621babe969307dd657783d672e2d8bdbd06493710da635bf63fa07", size
= 14350294, upload-time = "2026-09-24T13:16:11.865Z" },
+ { url =
"https://files.pythonhosted.org/packages/9c/f4/ae7dbd118425c850981d23efb850f0d9d7f6b8d2b852bde2767434f668b4/ty-0.0.84-py3-none-win32.whl",
hash =
"sha256:4bdc85f91cbaae35825f2b17bb4ac5de0563367875cb0f42b2bf07a1bf7ff2ba", size
= 13176439, upload-time = "2026-09-24T13:16:15.049Z" },
+ { url =
"https://files.pythonhosted.org/packages/29/ec/994d87252f065dda5a500bc8afc726d18f6582d81d6f4ff1feb8a267c800/ty-0.0.84-py3-none-win_amd64.whl",
hash =
"sha256:71cc9aa7a7c89d4e12c6a814e9c0c3310ad5bee44efedbd6f5a42d91e9ac0f0d", size
= 13962879, upload-time = "2026-09-24T13:16:18.191Z" },
+ { url =
"https://files.pythonhosted.org/packages/6d/1c/e6e91852b72566b1ab9aca504712857dfb89324c12092a5bd61d42d34427/ty-0.0.84-py3-none-win_arm64.whl",
hash =
"sha256:6c9d3718c4a0d318bc9c92af9b2aa85c3294e7dff54cf1d69ad79568f56516da", size
= 13656453, upload-time = "2026-09-24T13:16:21.51Z" },
]
[[package]]
@@ -1337,11 +1338,11 @@
[[package]]
name = "urllib3"
-version = "2.7.0"
+version = "2.8.0"
source = { registry = "https://pypi.org/simple" }
-sdist = { url =
"https://files.pythonhosted.org/packages/53/0c/06f8b233b8fd13b9e5ee11424ef85419ba0d8ba0b3138bf360be2ff56953/urllib3-2.7.0.tar.gz",
hash =
"sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c", size
= 433602, upload-time = "2026-05-07T16:13:18.596Z" }
+sdist = { url =
"https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz",
hash =
"sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63", size
= 458972, upload-time = "2026-09-15T19:29:36.253Z" }
wheels = [
- { url =
"https://files.pythonhosted.org/packages/7f/3e/5db95bcf282c52709639744ca2a8b149baccf648e39c8cc87553df9eae0c/urllib3-2.7.0-py3-none-any.whl",
hash =
"sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897", size
= 131087, upload-time = "2026-05-07T16:13:17.151Z" },
+ { url =
"https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl",
hash =
"sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3", size
= 135717, upload-time = "2026-09-15T19:29:34.577Z" },
]
[[package]]