langgraph-checkpoint-postgres 2.0.19__tar.gz → 2.0.20__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/PKG-INFO +5 -5
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/README.md +2 -2
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/__init__.py +23 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/aio.py +48 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/shallow.py +14 -1
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/store/postgres/aio.py +1 -1
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/store/postgres/base.py +1 -1
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/pyproject.toml +1 -1
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/_ainternal.py +0 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/_internal.py +0 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/base.py +0 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/checkpoint/postgres/py.typed +0 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/store/postgres/__init__.py +0 -0
- {langgraph_checkpoint_postgres-2.0.19 → langgraph_checkpoint_postgres-2.0.20}/langgraph/store/postgres/py.typed +0 -0
|
@@ -1,8 +1,7 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: langgraph-checkpoint-postgres
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.20
|
|
4
4
|
Summary: Library with a Postgres implementation of LangGraph checkpoint saver.
|
|
5
|
-
Home-page: https://www.github.com/langchain-ai/langgraph
|
|
6
5
|
License: MIT
|
|
7
6
|
Requires-Python: >=3.9.0,<4.0.0
|
|
8
7
|
Classifier: License :: OSI Approved :: MIT License
|
|
@@ -11,6 +10,7 @@ Classifier: Programming Language :: Python :: 3.9
|
|
|
11
10
|
Classifier: Programming Language :: Python :: 3.10
|
|
12
11
|
Classifier: Programming Language :: Python :: 3.11
|
|
13
12
|
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
14
|
Requires-Dist: langgraph-checkpoint (>=2.0.21,<3.0.0)
|
|
15
15
|
Requires-Dist: orjson (>=3.10.1)
|
|
16
16
|
Requires-Dist: psycopg (>=3.2.0,<4.0.0)
|
|
@@ -45,7 +45,7 @@ with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|
|
45
45
|
# call .setup() the first time you're using the checkpointer
|
|
46
46
|
checkpointer.setup()
|
|
47
47
|
checkpoint = {
|
|
48
|
-
"v":
|
|
48
|
+
"v": 2,
|
|
49
49
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
50
50
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
51
51
|
"channel_values": {
|
|
@@ -87,7 +87,7 @@ from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
|
|
87
87
|
|
|
88
88
|
async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|
89
89
|
checkpoint = {
|
|
90
|
-
"v":
|
|
90
|
+
"v": 2,
|
|
91
91
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
92
92
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
93
93
|
"channel_values": {
|
|
@@ -25,7 +25,7 @@ with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|
|
25
25
|
# call .setup() the first time you're using the checkpointer
|
|
26
26
|
checkpointer.setup()
|
|
27
27
|
checkpoint = {
|
|
28
|
-
"v":
|
|
28
|
+
"v": 2,
|
|
29
29
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
30
30
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
31
31
|
"channel_values": {
|
|
@@ -67,7 +67,7 @@ from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
|
|
67
67
|
|
|
68
68
|
async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|
69
69
|
checkpoint = {
|
|
70
|
-
"v":
|
|
70
|
+
"v": 2,
|
|
71
71
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
72
72
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
73
73
|
"channel_values": {
|
|
@@ -357,6 +357,29 @@ class PostgresSaver(BasePostgresSaver):
|
|
|
357
357
|
),
|
|
358
358
|
)
|
|
359
359
|
|
|
360
|
+
def delete_thread(self, thread_id: str) -> None:
|
|
361
|
+
"""Delete all checkpoints and writes associated with a thread ID.
|
|
362
|
+
|
|
363
|
+
Args:
|
|
364
|
+
thread_id (str): The thread ID to delete.
|
|
365
|
+
|
|
366
|
+
Returns:
|
|
367
|
+
None
|
|
368
|
+
"""
|
|
369
|
+
with self._cursor(pipeline=True) as cur:
|
|
370
|
+
cur.execute(
|
|
371
|
+
"DELETE FROM checkpoints WHERE thread_id = %s",
|
|
372
|
+
(str(thread_id),),
|
|
373
|
+
)
|
|
374
|
+
cur.execute(
|
|
375
|
+
"DELETE FROM checkpoint_blobs WHERE thread_id = %s",
|
|
376
|
+
(str(thread_id),),
|
|
377
|
+
)
|
|
378
|
+
cur.execute(
|
|
379
|
+
"DELETE FROM checkpoint_writes WHERE thread_id = %s",
|
|
380
|
+
(str(thread_id),),
|
|
381
|
+
)
|
|
382
|
+
|
|
360
383
|
@contextmanager
|
|
361
384
|
def _cursor(self, *, pipeline: bool = False) -> Iterator[Cursor[DictRow]]:
|
|
362
385
|
"""Create a database cursor as a context manager.
|
|
@@ -314,6 +314,29 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|
|
314
314
|
async with self._cursor(pipeline=True) as cur:
|
|
315
315
|
await cur.executemany(query, params)
|
|
316
316
|
|
|
317
|
+
async def adelete_thread(self, thread_id: str) -> None:
|
|
318
|
+
"""Delete all checkpoints and writes associated with a thread ID.
|
|
319
|
+
|
|
320
|
+
Args:
|
|
321
|
+
thread_id (str): The thread ID to delete.
|
|
322
|
+
|
|
323
|
+
Returns:
|
|
324
|
+
None
|
|
325
|
+
"""
|
|
326
|
+
async with self._cursor(pipeline=True) as cur:
|
|
327
|
+
await cur.execute(
|
|
328
|
+
"DELETE FROM checkpoints WHERE thread_id = %s",
|
|
329
|
+
(str(thread_id),),
|
|
330
|
+
)
|
|
331
|
+
await cur.execute(
|
|
332
|
+
"DELETE FROM checkpoint_blobs WHERE thread_id = %s",
|
|
333
|
+
(str(thread_id),),
|
|
334
|
+
)
|
|
335
|
+
await cur.execute(
|
|
336
|
+
"DELETE FROM checkpoint_writes WHERE thread_id = %s",
|
|
337
|
+
(str(thread_id),),
|
|
338
|
+
)
|
|
339
|
+
|
|
317
340
|
@asynccontextmanager
|
|
318
341
|
async def _cursor(
|
|
319
342
|
self, *, pipeline: bool = False
|
|
@@ -481,5 +504,30 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|
|
481
504
|
self.aput_writes(config, writes, task_id, task_path), self.loop
|
|
482
505
|
).result()
|
|
483
506
|
|
|
507
|
+
def delete_thread(self, thread_id: str) -> None:
|
|
508
|
+
"""Delete all checkpoints and writes associated with a thread ID.
|
|
509
|
+
|
|
510
|
+
Args:
|
|
511
|
+
thread_id (str): The thread ID to delete.
|
|
512
|
+
|
|
513
|
+
Returns:
|
|
514
|
+
None
|
|
515
|
+
"""
|
|
516
|
+
try:
|
|
517
|
+
# check if we are in the main thread, only bg threads can block
|
|
518
|
+
# we don't check in other methods to avoid the overhead
|
|
519
|
+
if asyncio.get_running_loop() is self.loop:
|
|
520
|
+
raise asyncio.InvalidStateError(
|
|
521
|
+
"Synchronous calls to AsyncPostgresSaver are only allowed from a "
|
|
522
|
+
"different thread. From the main thread, use the async interface. "
|
|
523
|
+
"For example, use `await checkpointer.aget_tuple(...)` or `await "
|
|
524
|
+
"graph.ainvoke(...)`."
|
|
525
|
+
)
|
|
526
|
+
except RuntimeError:
|
|
527
|
+
pass
|
|
528
|
+
return asyncio.run_coroutine_threadsafe(
|
|
529
|
+
self.adelete_thread(thread_id), self.loop
|
|
530
|
+
).result()
|
|
531
|
+
|
|
484
532
|
|
|
485
533
|
__all__ = ["AsyncPostgresSaver", "AsyncShallowPostgresSaver", "Conn"]
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import asyncio
|
|
2
2
|
import threading
|
|
3
|
+
import warnings
|
|
3
4
|
from collections.abc import AsyncIterator, Iterator, Sequence
|
|
4
5
|
from contextlib import asynccontextmanager, contextmanager
|
|
5
6
|
from typing import Any, Optional
|
|
@@ -150,7 +151,7 @@ def _dump_blobs(
|
|
|
150
151
|
checkpoint_ns: str,
|
|
151
152
|
values: dict[str, Any],
|
|
152
153
|
versions: ChannelVersions,
|
|
153
|
-
) -> list[tuple[str, str, str, str,
|
|
154
|
+
) -> list[tuple[str, str, str, str, Optional[bytes]]]:
|
|
154
155
|
if not versions:
|
|
155
156
|
return []
|
|
156
157
|
|
|
@@ -188,6 +189,12 @@ class ShallowPostgresSaver(BasePostgresSaver):
|
|
|
188
189
|
pipe: Optional[Pipeline] = None,
|
|
189
190
|
serde: Optional[SerializerProtocol] = None,
|
|
190
191
|
) -> None:
|
|
192
|
+
warnings.warn(
|
|
193
|
+
"ShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. "
|
|
194
|
+
"Use PostgresSaver instead, and invoke the graph with `graph.invoke(..., checkpoint_during=False)`.",
|
|
195
|
+
DeprecationWarning,
|
|
196
|
+
stacklevel=2,
|
|
197
|
+
)
|
|
191
198
|
super().__init__(serde=serde)
|
|
192
199
|
if isinstance(conn, ConnectionPool) and pipe is not None:
|
|
193
200
|
raise ValueError(
|
|
@@ -528,6 +535,12 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
|
|
|
528
535
|
pipe: Optional[AsyncPipeline] = None,
|
|
529
536
|
serde: Optional[SerializerProtocol] = None,
|
|
530
537
|
) -> None:
|
|
538
|
+
warnings.warn(
|
|
539
|
+
"AsyncShallowPostgresSaver is deprecated as of version 2.0.20 and will be removed in 3.0.0. "
|
|
540
|
+
"Use AsyncPostgresSaver instead, and invoke the graph with `await graph.ainvoke(..., checkpoint_during=False)`.",
|
|
541
|
+
DeprecationWarning,
|
|
542
|
+
stacklevel=2,
|
|
543
|
+
)
|
|
531
544
|
super().__init__(serde=serde)
|
|
532
545
|
if isinstance(conn, AsyncConnectionPool) and pipe is not None:
|
|
533
546
|
raise ValueError(
|
|
@@ -78,7 +78,7 @@ class AsyncPostgresStore(AsyncBatchedBaseStore, BasePostgresStore[_ainternal.Con
|
|
|
78
78
|
await store.aput(("docs",), "doc3", {"text": "Other guide"}, index=False) # don't index
|
|
79
79
|
|
|
80
80
|
# Search by similarity
|
|
81
|
-
results = await store.asearch(("docs",), "programming guides", limit=2)
|
|
81
|
+
results = await store.asearch(("docs",), query="programming guides", limit=2)
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
Using connection pooling for better performance:
|
|
@@ -684,7 +684,7 @@ class PostgresStore(BaseStore, BasePostgresStore[_pg_internal.Conn]):
|
|
|
684
684
|
store.put(("docs",), "doc2", {"text": "Other guide"}, index=False) # don't index
|
|
685
685
|
|
|
686
686
|
# Search by similarity
|
|
687
|
-
results = store.search(("docs",), "programming guides", limit=2)
|
|
687
|
+
results = store.search(("docs",), query="programming guides", limit=2)
|
|
688
688
|
```
|
|
689
689
|
|
|
690
690
|
Note:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|