langgraph-checkpoint-oceanbase-es 3.0.0__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_oceanbase_es-3.0.0/.claude/settings.local.json +7 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_lint.yml +83 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_test.yml +68 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_test_release.yml +88 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/ci.yml +44 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/release.yml +59 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/.gitignore +3 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/LICENSE +21 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/Makefile +99 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/PKG-INFO +147 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/README.md +117 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/__init__.py +26 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/_ainternal.py +91 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/_internal.py +87 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/aio.py +105 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/aio_base.py +382 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/asyncmy.py +99 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/base.py +398 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/pymysql.py +383 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/shallow.py +437 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/utils.py +152 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/__init__.py +7 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/aio.py +370 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/aio_base.py +278 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/asyncmy.py +72 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/base.py +380 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/es_backend.py +731 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/pymysql.py +347 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/utils.py +58 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/__init__.py +0 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/agents.py +43 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/any_int.py +6 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/any_str.py +92 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest.py +149 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest_checkpointer.py +173 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest_store.py +161 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/fake_tracer.py +91 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/messages.py +50 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_checkpoint_migration.py +1733 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_interruption.py +92 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_large_cases.py +6512 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_large_cases_async.py +3475 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_pregel.py +5764 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_pregel_async.py +7040 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_react_agent.py +168 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/pyproject.toml +101 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/test_local_checkpoint.py +378 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/__init__.py +0 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/compose-mariadb.yml +25 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/compose-mysql.yml +25 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/conftest.py +59 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/conftest.py +1 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/run_standalone.py +438 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/test_oceanbase.py +561 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_async.py +590 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_async_store.py +588 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_store.py +362 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_sync.py +461 -0
- langgraph_checkpoint_oceanbase_es-3.0.0/uv.lock +1428 -0
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
name: lint
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call
|
|
5
|
+
|
|
6
|
+
env:
|
|
7
|
+
# This env var allows us to get inline annotations when ruff has complaints.
|
|
8
|
+
RUFF_OUTPUT_FORMAT: github
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
build:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
strategy:
|
|
14
|
+
matrix:
|
|
15
|
+
# Only lint on the min and max supported Python versions.
|
|
16
|
+
# It's extremely unlikely that there's a lint issue on any version in between
|
|
17
|
+
# that doesn't show up on the min or max versions.
|
|
18
|
+
#
|
|
19
|
+
# GitHub rate-limits how many jobs can be running at any one time.
|
|
20
|
+
# Starting new jobs is also relatively slow,
|
|
21
|
+
# so linting on fewer versions makes CI faster.
|
|
22
|
+
python-version:
|
|
23
|
+
- "3.12"
|
|
24
|
+
name: "lint #${{ matrix.python-version }}"
|
|
25
|
+
steps:
|
|
26
|
+
- uses: actions/checkout@v6
|
|
27
|
+
- name: Get changed files
|
|
28
|
+
id: changed-files
|
|
29
|
+
uses: Ana06/get-changed-files@v2.3.0
|
|
30
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
31
|
+
if: steps.changed-files.outputs.all
|
|
32
|
+
uses: astral-sh/setup-uv@v7
|
|
33
|
+
with:
|
|
34
|
+
python-version: ${{ matrix.python-version }}
|
|
35
|
+
enable-cache: true
|
|
36
|
+
cache-suffix: lint-${{ inputs.working-directory }}
|
|
37
|
+
|
|
38
|
+
- name: Install dependencies
|
|
39
|
+
if: steps.changed-files.outputs.all
|
|
40
|
+
run: uv sync --frozen --group dev
|
|
41
|
+
|
|
42
|
+
- name: Get .mypy_cache to speed up mypy
|
|
43
|
+
if: steps.changed-files.outputs.all
|
|
44
|
+
uses: actions/cache@v4
|
|
45
|
+
env:
|
|
46
|
+
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
|
47
|
+
with:
|
|
48
|
+
path: |
|
|
49
|
+
.mypy_cache
|
|
50
|
+
key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
|
|
51
|
+
|
|
52
|
+
- name: Analysing package code with our lint
|
|
53
|
+
if: steps.changed-files.outputs.all
|
|
54
|
+
run: |
|
|
55
|
+
if make lint_package > /dev/null 2>&1; then
|
|
56
|
+
make lint_package
|
|
57
|
+
else
|
|
58
|
+
echo "lint_package command not found, using lint instead"
|
|
59
|
+
make lint
|
|
60
|
+
fi
|
|
61
|
+
|
|
62
|
+
- name: Install test dependencies
|
|
63
|
+
if: steps.changed-files.outputs.all
|
|
64
|
+
run: uv sync --group dev
|
|
65
|
+
|
|
66
|
+
- name: Get .mypy_cache_test to speed up mypy
|
|
67
|
+
if: steps.changed-files.outputs.all
|
|
68
|
+
uses: actions/cache@v4
|
|
69
|
+
env:
|
|
70
|
+
SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2"
|
|
71
|
+
with:
|
|
72
|
+
path: |
|
|
73
|
+
.mypy_cache_test
|
|
74
|
+
key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('uv.lock') }}
|
|
75
|
+
|
|
76
|
+
- name: Analysing tests with our lint
|
|
77
|
+
if: steps.changed-files.outputs.all
|
|
78
|
+
run: |
|
|
79
|
+
if make lint_tests > /dev/null 2>&1; then
|
|
80
|
+
make lint_tests
|
|
81
|
+
else
|
|
82
|
+
echo "lint_tests command not found, skipping step"
|
|
83
|
+
fi
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
name: test
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call
|
|
5
|
+
|
|
6
|
+
jobs:
|
|
7
|
+
build:
|
|
8
|
+
runs-on: ubuntu-latest
|
|
9
|
+
strategy:
|
|
10
|
+
matrix:
|
|
11
|
+
database:
|
|
12
|
+
- db: "mysql"
|
|
13
|
+
version: "9.5"
|
|
14
|
+
- db: "mysql"
|
|
15
|
+
version: "8"
|
|
16
|
+
- db: "mysql"
|
|
17
|
+
version: "8.0.19"
|
|
18
|
+
- db: "mariadb"
|
|
19
|
+
version: "11"
|
|
20
|
+
- db: "mariadb"
|
|
21
|
+
version: "10"
|
|
22
|
+
python-version:
|
|
23
|
+
- "3.10"
|
|
24
|
+
- "3.11"
|
|
25
|
+
- "3.12"
|
|
26
|
+
- "3.13"
|
|
27
|
+
- "3.14"
|
|
28
|
+
|
|
29
|
+
name: "test python ${{ matrix.python-version }} | ${{ matrix.database.db }} ${{ matrix.database.version }}"
|
|
30
|
+
steps:
|
|
31
|
+
- uses: actions/checkout@v6
|
|
32
|
+
- name: Set up Python ${{ matrix.python-version }}
|
|
33
|
+
uses: astral-sh/setup-uv@v7
|
|
34
|
+
with:
|
|
35
|
+
python-version: ${{ matrix.python-version }}
|
|
36
|
+
enable-cache: true
|
|
37
|
+
cache-suffix: test-${{ inputs.working-directory }}
|
|
38
|
+
|
|
39
|
+
- name: Install dependencies
|
|
40
|
+
shell: bash
|
|
41
|
+
run: uv sync --frozen --group dev
|
|
42
|
+
|
|
43
|
+
- name: Run MySQL tests
|
|
44
|
+
if: ${{ matrix.database.db == 'mysql' }}
|
|
45
|
+
shell: bash
|
|
46
|
+
env:
|
|
47
|
+
MYSQL_VERSIONS: ${{ matrix.database.version }}
|
|
48
|
+
run: make test
|
|
49
|
+
|
|
50
|
+
- name: Run MariaDB tests
|
|
51
|
+
if: ${{ matrix.database.db == 'mariadb' }}
|
|
52
|
+
shell: bash
|
|
53
|
+
env:
|
|
54
|
+
MARIADB_VERSIONS: ${{ matrix.database.version }}
|
|
55
|
+
run: |
|
|
56
|
+
make test-mariadb
|
|
57
|
+
|
|
58
|
+
- name: Ensure the tests did not create any additional files
|
|
59
|
+
shell: bash
|
|
60
|
+
run: |
|
|
61
|
+
set -eu
|
|
62
|
+
|
|
63
|
+
STATUS="$(git status)"
|
|
64
|
+
echo "$STATUS"
|
|
65
|
+
|
|
66
|
+
# grep will exit non-zero if the target message isn't found,
|
|
67
|
+
# and `set -e` above will cause the step to fail.
|
|
68
|
+
echo "$STATUS" | grep 'nothing to commit, working tree clean'
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
name: test-release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
workflow_call
|
|
5
|
+
|
|
6
|
+
env:
|
|
7
|
+
PYTHON_VERSION: "3.10"
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
build:
|
|
11
|
+
if: github.ref == 'refs/heads/main'
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
|
|
14
|
+
outputs:
|
|
15
|
+
pkg-name: ${{ steps.check-version.outputs.pkg-name }}
|
|
16
|
+
version: ${{ steps.check-version.outputs.version }}
|
|
17
|
+
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v6
|
|
20
|
+
|
|
21
|
+
- name: Set up Python
|
|
22
|
+
uses: astral-sh/setup-uv@v7
|
|
23
|
+
with:
|
|
24
|
+
python-version: ${{ env.PYTHON_VERSION }}
|
|
25
|
+
enable-cache: true
|
|
26
|
+
cache-suffix: "release"
|
|
27
|
+
|
|
28
|
+
# We want to keep this build stage *separate* from the release stage,
|
|
29
|
+
# so that there's no sharing of permissions between them.
|
|
30
|
+
# The release stage has trusted publishing and GitHub repo contents write access,
|
|
31
|
+
# and we want to keep the scope of that access limited just to the release job.
|
|
32
|
+
# Otherwise, a malicious `build` step (e.g. via a compromised dependency)
|
|
33
|
+
# could get access to our GitHub or PyPI credentials.
|
|
34
|
+
#
|
|
35
|
+
# Per the trusted publishing GitHub Action:
|
|
36
|
+
# > It is strongly advised to separate jobs for building [...]
|
|
37
|
+
# > from the publish job.
|
|
38
|
+
# https://github.com/pypa/gh-action-pypi-publish#non-goals
|
|
39
|
+
- name: Build project for distribution
|
|
40
|
+
run: uv build
|
|
41
|
+
|
|
42
|
+
- name: Upload build
|
|
43
|
+
uses: actions/upload-artifact@v4
|
|
44
|
+
with:
|
|
45
|
+
name: test-dist
|
|
46
|
+
path: dist/
|
|
47
|
+
|
|
48
|
+
- name: Check Version
|
|
49
|
+
id: check-version
|
|
50
|
+
shell: bash
|
|
51
|
+
run: |
|
|
52
|
+
echo pkg-name=$(grep -m 1 "^name = " pyproject.toml | cut -d '"' -f 2)
|
|
53
|
+
echo version=$(grep -m 1 "^version = " pyproject.toml | cut -d '"' -f 2)
|
|
54
|
+
|
|
55
|
+
publish:
|
|
56
|
+
needs:
|
|
57
|
+
- build
|
|
58
|
+
runs-on: ubuntu-latest
|
|
59
|
+
permissions:
|
|
60
|
+
# This permission is used for trusted publishing:
|
|
61
|
+
# https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/
|
|
62
|
+
#
|
|
63
|
+
# Trusted publishing has to also be configured on PyPI for each package:
|
|
64
|
+
# https://docs.pypi.org/trusted-publishers/adding-a-publisher/
|
|
65
|
+
id-token: write
|
|
66
|
+
|
|
67
|
+
steps:
|
|
68
|
+
- uses: actions/checkout@v6
|
|
69
|
+
|
|
70
|
+
- uses: actions/download-artifact@v4
|
|
71
|
+
with:
|
|
72
|
+
name: test-dist
|
|
73
|
+
path: dist/
|
|
74
|
+
|
|
75
|
+
- name: Publish to test PyPI
|
|
76
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
77
|
+
with:
|
|
78
|
+
packages-dir: dist/
|
|
79
|
+
verbose: true
|
|
80
|
+
print-hash: true
|
|
81
|
+
repository-url: https://test.pypi.org/legacy/
|
|
82
|
+
|
|
83
|
+
# We overwrite any existing distributions with the same name and version.
|
|
84
|
+
# This is *only for CI use* and is *extremely dangerous* otherwise!
|
|
85
|
+
# https://github.com/pypa/gh-action-pypi-publish#tolerating-release-package-file-duplicates
|
|
86
|
+
skip-existing: true
|
|
87
|
+
# Temp workaround since attestations are on by default as of gh-action-pypi-publish v1.11.0
|
|
88
|
+
attestations: false
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: CI
|
|
3
|
+
|
|
4
|
+
on:
|
|
5
|
+
push:
|
|
6
|
+
branches: [oceanbase-es]
|
|
7
|
+
pull_request:
|
|
8
|
+
|
|
9
|
+
# If another push to the same PR or branch happens while this workflow is still running,
|
|
10
|
+
# cancel the earlier run in favor of the next run.
|
|
11
|
+
#
|
|
12
|
+
# There's no point in testing an outdated version of the code. GitHub only allows
|
|
13
|
+
# a limited number of job runners to be active at the same time, so it's better to cancel
|
|
14
|
+
# pointless jobs early so that more useful jobs can run sooner.
|
|
15
|
+
concurrency:
|
|
16
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
17
|
+
cancel-in-progress: true
|
|
18
|
+
|
|
19
|
+
jobs:
|
|
20
|
+
lint:
|
|
21
|
+
uses: ./.github/workflows/_lint.yml
|
|
22
|
+
secrets: inherit
|
|
23
|
+
|
|
24
|
+
test:
|
|
25
|
+
uses: ./.github/workflows/_test.yml
|
|
26
|
+
secrets: inherit
|
|
27
|
+
|
|
28
|
+
ci_success:
|
|
29
|
+
name: "CI Success"
|
|
30
|
+
needs: [lint, test]
|
|
31
|
+
if: |
|
|
32
|
+
always()
|
|
33
|
+
runs-on: ubuntu-latest
|
|
34
|
+
env:
|
|
35
|
+
JOBS_JSON: ${{ toJSON(needs) }}
|
|
36
|
+
RESULTS_JSON: ${{ toJSON(needs.*.result) }}
|
|
37
|
+
EXIT_CODE: ${{!contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && '0' || '1'}}
|
|
38
|
+
steps:
|
|
39
|
+
- name: "CI Success"
|
|
40
|
+
run: |
|
|
41
|
+
echo $JOBS_JSON
|
|
42
|
+
echo $RESULTS_JSON
|
|
43
|
+
echo "Exiting with $EXIT_CODE"
|
|
44
|
+
exit $EXIT_CODE
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
name: Release to PyPI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags:
|
|
6
|
+
- 'v*'
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
inputs:
|
|
11
|
+
tag:
|
|
12
|
+
description: 'Tag to release (e.g., v3.0.0)'
|
|
13
|
+
required: true
|
|
14
|
+
type: string
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
build-and-publish:
|
|
18
|
+
name: Build and publish to PyPI
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
environment:
|
|
21
|
+
name: pypi
|
|
22
|
+
url: https://pypi.org/p/langgraph-checkpoint-oceanbase-es
|
|
23
|
+
permissions:
|
|
24
|
+
id-token: write # Required for trusted publishing
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout code
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
with:
|
|
30
|
+
ref: ${{ github.event.inputs.tag || github.ref }}
|
|
31
|
+
|
|
32
|
+
- name: Set up Python
|
|
33
|
+
uses: actions/setup-python@v5
|
|
34
|
+
with:
|
|
35
|
+
python-version: '3.11'
|
|
36
|
+
|
|
37
|
+
- name: Install build dependencies
|
|
38
|
+
run: |
|
|
39
|
+
python -m pip install --upgrade pip
|
|
40
|
+
pip install build twine
|
|
41
|
+
|
|
42
|
+
- name: Build package
|
|
43
|
+
run: python -m build
|
|
44
|
+
|
|
45
|
+
- name: Check package
|
|
46
|
+
run: twine check dist/*
|
|
47
|
+
|
|
48
|
+
- name: Publish to PyPI
|
|
49
|
+
env:
|
|
50
|
+
TWINE_USERNAME: __token__
|
|
51
|
+
TWINE_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
|
|
52
|
+
run: twine upload dist/*
|
|
53
|
+
|
|
54
|
+
- name: Upload artifacts
|
|
55
|
+
uses: actions/upload-artifact@v4
|
|
56
|
+
if: always()
|
|
57
|
+
with:
|
|
58
|
+
name: python-package-distributions
|
|
59
|
+
path: dist/
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 Theodore Ni
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
.PHONY: test test_watch lint format
|
|
2
|
+
|
|
3
|
+
######################
|
|
4
|
+
# TESTING AND COVERAGE
|
|
5
|
+
######################
|
|
6
|
+
|
|
7
|
+
start-mysql:
|
|
8
|
+
MYSQL_VERSION=$(MYSQL_VERSION) docker compose -f tests/compose-mysql.yml up -V --force-recreate --wait || ( \
|
|
9
|
+
echo "Failed to start MySQL, printing logs..."; \
|
|
10
|
+
docker compose -f tests/compose-mysql.yml logs; \
|
|
11
|
+
exit 1 \
|
|
12
|
+
)
|
|
13
|
+
|
|
14
|
+
stop-mysql:
|
|
15
|
+
docker compose -f tests/compose-mysql.yml down --remove-orphans -v
|
|
16
|
+
|
|
17
|
+
MYSQL_VERSIONS ?= 8
|
|
18
|
+
test_mysql_version:
|
|
19
|
+
@echo "Testing MySQL $(MYSQL_VERSION)"
|
|
20
|
+
@MYSQL_VERSION=$(MYSQL_VERSION) make start-mysql
|
|
21
|
+
@uv run pytest --ignore=langgraph-tests $(TEST) && \
|
|
22
|
+
uv run pytest -n auto --dist worksteal langgraph-tests || ( \
|
|
23
|
+
EXIT_CODE=$$?; \
|
|
24
|
+
make stop-mysql; \
|
|
25
|
+
echo "Finished testing MySQL $(MYSQL_VERSION); Exit code: $$EXIT_CODE"; \
|
|
26
|
+
exit $$EXIT_CODE \
|
|
27
|
+
)
|
|
28
|
+
|
|
29
|
+
test:
|
|
30
|
+
@for version in $(MYSQL_VERSIONS); do \
|
|
31
|
+
if ! make test_mysql_version MYSQL_VERSION=$$version; then \
|
|
32
|
+
echo "Test failed for MySQL $$version"; \
|
|
33
|
+
exit 1; \
|
|
34
|
+
fi; \
|
|
35
|
+
done
|
|
36
|
+
@echo "All MySQL versions tested successfully"
|
|
37
|
+
|
|
38
|
+
start-mariadb:
|
|
39
|
+
MARIADB_VERSION=$(MARIADB_VERSION) docker compose -f tests/compose-mariadb.yml up -V --force-recreate --wait || ( \
|
|
40
|
+
echo "Failed to start MariaDB, printing logs..."; \
|
|
41
|
+
docker compose -f tests/compose-mariadb.yml logs; \
|
|
42
|
+
exit 1 \
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
stop-mariadb:
|
|
46
|
+
docker compose -f tests/compose-mariadb.yml down --remove-orphans -v
|
|
47
|
+
|
|
48
|
+
MARIADB_VERSIONS ?= 10
|
|
49
|
+
test_mariadb_version:
|
|
50
|
+
@echo "Testing MariaDB $(MARIADB_VERSION)"
|
|
51
|
+
@MARIADB_VERSION=$(MARIADB_VERSION) make start-mariadb
|
|
52
|
+
@uv run pytest --ignore=langgraph-tests $(TEST) && \
|
|
53
|
+
uv run pytest -n auto --dist worksteal langgraph-tests || ( \
|
|
54
|
+
EXIT_CODE=$$?; \
|
|
55
|
+
make stop-mariadb; \
|
|
56
|
+
echo "Finished testing MariaDB $(MARIADB_VERSION); Exit code: $$EXIT_CODE"; \
|
|
57
|
+
exit $$EXIT_CODE \
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
test-mariadb:
|
|
61
|
+
@for version in $(MARIADB_VERSIONS); do \
|
|
62
|
+
if ! make test_mariadb_version MARIADB_VERSION=$$version; then \
|
|
63
|
+
echo "Test failed for MariaDB $$version"; \
|
|
64
|
+
exit 1; \
|
|
65
|
+
fi; \
|
|
66
|
+
done
|
|
67
|
+
@echo "All MariaDB versions tested successfully"
|
|
68
|
+
|
|
69
|
+
TEST ?= .
|
|
70
|
+
test_watch:
|
|
71
|
+
MYSQL_VERSION=$(MYSQL_VERSION) make start-mysql; \
|
|
72
|
+
uv run ptw $(TEST); \
|
|
73
|
+
EXIT_CODE=$$?; \
|
|
74
|
+
make stop-mysql; \
|
|
75
|
+
exit $$EXIT_CODE
|
|
76
|
+
|
|
77
|
+
######################
|
|
78
|
+
# LINTING AND FORMATTING
|
|
79
|
+
######################
|
|
80
|
+
|
|
81
|
+
# Define a variable for Python and notebook files.
|
|
82
|
+
PYTHON_FILES=.
|
|
83
|
+
MYPY_CACHE=.mypy_cache
|
|
84
|
+
lint format: PYTHON_FILES=.
|
|
85
|
+
lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$')
|
|
86
|
+
lint_package: PYTHON_FILES=langgraph
|
|
87
|
+
lint_tests: PYTHON_FILES=tests
|
|
88
|
+
lint_tests: MYPY_CACHE=.mypy_cache_test
|
|
89
|
+
|
|
90
|
+
lint lint_diff lint_package lint_tests:
|
|
91
|
+
uv run ruff check .
|
|
92
|
+
[ "$(PYTHON_FILES)" = "" ] || uv run ruff format $(PYTHON_FILES) --diff
|
|
93
|
+
[ "$(PYTHON_FILES)" = "" ] || uv run ruff check --select I $(PYTHON_FILES)
|
|
94
|
+
[ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE)
|
|
95
|
+
[ "$(PYTHON_FILES)" = "" ] || uv run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE)
|
|
96
|
+
|
|
97
|
+
format format_diff:
|
|
98
|
+
uv run ruff format $(PYTHON_FILES)
|
|
99
|
+
uv run ruff check --select I --fix $(PYTHON_FILES)
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: langgraph-checkpoint-oceanbase-es
|
|
3
|
+
Version: 3.0.0
|
|
4
|
+
Summary: Library with an OceanBase/MySQL implementation of LangGraph checkpoint saver with Elasticsearch vector search support.
|
|
5
|
+
Project-URL: Repository, https://www.github.com/tjni/langgraph-checkpoint-mysql
|
|
6
|
+
Author-email: Theodore Ni <dev@ted.bio>
|
|
7
|
+
License-Expression: MIT
|
|
8
|
+
License-File: LICENSE
|
|
9
|
+
Keywords: checkpoint,elasticsearch,langgraph,mysql,oceanbase,vector-search
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Requires-Python: >=3.10
|
|
20
|
+
Requires-Dist: langgraph-checkpoint>=2.1.2
|
|
21
|
+
Requires-Dist: orjson>=3.10.1
|
|
22
|
+
Requires-Dist: typing-extensions>=4.12.2
|
|
23
|
+
Provides-Extra: aiomysql
|
|
24
|
+
Requires-Dist: aiomysql>=0.2.0; extra == 'aiomysql'
|
|
25
|
+
Provides-Extra: asyncmy
|
|
26
|
+
Requires-Dist: asyncmy>=0.2.10; extra == 'asyncmy'
|
|
27
|
+
Provides-Extra: pymysql
|
|
28
|
+
Requires-Dist: pymysql>=1.1.1; extra == 'pymysql'
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# LangGraph Checkpoint MySQL
|
|
32
|
+
|
|
33
|
+
Implementation of LangGraph CheckpointSaver that uses MySQL.
|
|
34
|
+
|
|
35
|
+
> [!TIP]
|
|
36
|
+
> The code in this repository tries to mimic the code in [langgraph-checkpoint-postgres](https://github.com/langchain-ai/langgraph/tree/main/libs/checkpoint-postgres) as much as possible to enable keeping in sync with the official checkpointer implementation.
|
|
37
|
+
|
|
38
|
+
> [!NOTE]
|
|
39
|
+
> In order to keep the queries close to the Postgres queries, we use features that require MySQL >= 8.0.19 or MariaDB >= 10.7.1.
|
|
40
|
+
|
|
41
|
+
> [!NOTE]
|
|
42
|
+
> MySQL >= 9.6.0 discontinued using the MD5 function in generated columns, but we have not created a migration path for this yet.
|
|
43
|
+
|
|
44
|
+
## Dependencies
|
|
45
|
+
|
|
46
|
+
- To use synchronous `PyMySQLSaver`, install `langgraph-checkpoint-mysql[pymysql]`.
|
|
47
|
+
- To use asynchronous `AIOMySQLSaver`, install `langgraph-checkpoint-mysql[aiomysql]`.
|
|
48
|
+
- To use asynchronous `AsyncMySaver`, install `langgraph-checkpoint-mysql[asyncmy]`.
|
|
49
|
+
|
|
50
|
+
There is currently no support for other drivers.
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
> [!IMPORTANT]
|
|
55
|
+
> When using MySQL checkpointers for the first time, make sure to call `.setup()` method on them to create required tables. See example below.
|
|
56
|
+
|
|
57
|
+
> [!IMPORTANT]
|
|
58
|
+
> When manually creating MySQL connections and passing them to `PyMySQLSaver` or `AIOMySQLSaver`, make sure to include `autocommit=True`.
|
|
59
|
+
>
|
|
60
|
+
> **Why this parameter is required:**
|
|
61
|
+
> - `autocommit=True`: Required for the `.setup()` method to properly commit the checkpoint tables to the database. Without this, table creation may not be persisted.
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from langgraph.checkpoint.mysql.pymysql import PyMySQLSaver
|
|
65
|
+
|
|
66
|
+
write_config = {"configurable": {"thread_id": "1", "checkpoint_ns": ""}}
|
|
67
|
+
read_config = {"configurable": {"thread_id": "1"}}
|
|
68
|
+
|
|
69
|
+
DB_URI = "mysql://mysql:mysql@localhost:3306/mysql"
|
|
70
|
+
with PyMySQLSaver.from_conn_string(DB_URI) as checkpointer:
|
|
71
|
+
# call .setup() the first time you're using the checkpointer
|
|
72
|
+
checkpointer.setup()
|
|
73
|
+
checkpoint = {
|
|
74
|
+
"v": 4,
|
|
75
|
+
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
76
|
+
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
77
|
+
"channel_values": {
|
|
78
|
+
"my_key": "meow",
|
|
79
|
+
"node": "node"
|
|
80
|
+
},
|
|
81
|
+
"channel_versions": {
|
|
82
|
+
"__start__": 2,
|
|
83
|
+
"my_key": 3,
|
|
84
|
+
"start:node": 3,
|
|
85
|
+
"node": 3
|
|
86
|
+
},
|
|
87
|
+
"versions_seen": {
|
|
88
|
+
"__input__": {},
|
|
89
|
+
"__start__": {
|
|
90
|
+
"__start__": 1
|
|
91
|
+
},
|
|
92
|
+
"node": {
|
|
93
|
+
"start:node": 2
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
# store checkpoint
|
|
99
|
+
checkpointer.put(write_config, checkpoint, {}, {})
|
|
100
|
+
|
|
101
|
+
# load checkpoint
|
|
102
|
+
checkpointer.get(read_config)
|
|
103
|
+
|
|
104
|
+
# list checkpoints
|
|
105
|
+
list(checkpointer.list(read_config))
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Async
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
from langgraph.checkpoint.mysql.aio import AIOMySQLSaver
|
|
112
|
+
|
|
113
|
+
async with AIOMySQLSaver.from_conn_string(DB_URI) as checkpointer:
|
|
114
|
+
checkpoint = {
|
|
115
|
+
"v": 4,
|
|
116
|
+
"ts": "2024-07-31T20:14:19.804150+00:00",
|
|
117
|
+
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
|
118
|
+
"channel_values": {
|
|
119
|
+
"my_key": "meow",
|
|
120
|
+
"node": "node"
|
|
121
|
+
},
|
|
122
|
+
"channel_versions": {
|
|
123
|
+
"__start__": 2,
|
|
124
|
+
"my_key": 3,
|
|
125
|
+
"start:node": 3,
|
|
126
|
+
"node": 3
|
|
127
|
+
},
|
|
128
|
+
"versions_seen": {
|
|
129
|
+
"__input__": {},
|
|
130
|
+
"__start__": {
|
|
131
|
+
"__start__": 1
|
|
132
|
+
},
|
|
133
|
+
"node": {
|
|
134
|
+
"start:node": 2
|
|
135
|
+
}
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
# store checkpoint
|
|
140
|
+
await checkpointer.aput(write_config, checkpoint, {}, {})
|
|
141
|
+
|
|
142
|
+
# load checkpoint
|
|
143
|
+
await checkpointer.aget(read_config)
|
|
144
|
+
|
|
145
|
+
# list checkpoints
|
|
146
|
+
[c async for c in checkpointer.alist(read_config)]
|
|
147
|
+
```
|