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.
Files changed (59) hide show
  1. langgraph_checkpoint_oceanbase_es-3.0.0/.claude/settings.local.json +7 -0
  2. langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_lint.yml +83 -0
  3. langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_test.yml +68 -0
  4. langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/_test_release.yml +88 -0
  5. langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/ci.yml +44 -0
  6. langgraph_checkpoint_oceanbase_es-3.0.0/.github/workflows/release.yml +59 -0
  7. langgraph_checkpoint_oceanbase_es-3.0.0/.gitignore +3 -0
  8. langgraph_checkpoint_oceanbase_es-3.0.0/LICENSE +21 -0
  9. langgraph_checkpoint_oceanbase_es-3.0.0/Makefile +99 -0
  10. langgraph_checkpoint_oceanbase_es-3.0.0/PKG-INFO +147 -0
  11. langgraph_checkpoint_oceanbase_es-3.0.0/README.md +117 -0
  12. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/__init__.py +26 -0
  13. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/_ainternal.py +91 -0
  14. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/_internal.py +87 -0
  15. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/aio.py +105 -0
  16. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/aio_base.py +382 -0
  17. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/asyncmy.py +99 -0
  18. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/base.py +398 -0
  19. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/pymysql.py +383 -0
  20. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/shallow.py +437 -0
  21. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/checkpoint/oceanbase/utils.py +152 -0
  22. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/__init__.py +7 -0
  23. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/aio.py +370 -0
  24. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/aio_base.py +278 -0
  25. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/asyncmy.py +72 -0
  26. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/base.py +380 -0
  27. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/es_backend.py +731 -0
  28. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/pymysql.py +347 -0
  29. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph/store/oceanbase/utils.py +58 -0
  30. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/__init__.py +0 -0
  31. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/agents.py +43 -0
  32. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/any_int.py +6 -0
  33. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/any_str.py +92 -0
  34. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest.py +149 -0
  35. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest_checkpointer.py +173 -0
  36. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/conftest_store.py +161 -0
  37. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/fake_tracer.py +91 -0
  38. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/messages.py +50 -0
  39. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_checkpoint_migration.py +1733 -0
  40. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_interruption.py +92 -0
  41. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_large_cases.py +6512 -0
  42. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_large_cases_async.py +3475 -0
  43. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_pregel.py +5764 -0
  44. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_pregel_async.py +7040 -0
  45. langgraph_checkpoint_oceanbase_es-3.0.0/langgraph-tests/tests/test_react_agent.py +168 -0
  46. langgraph_checkpoint_oceanbase_es-3.0.0/pyproject.toml +101 -0
  47. langgraph_checkpoint_oceanbase_es-3.0.0/test_local_checkpoint.py +378 -0
  48. langgraph_checkpoint_oceanbase_es-3.0.0/tests/__init__.py +0 -0
  49. langgraph_checkpoint_oceanbase_es-3.0.0/tests/compose-mariadb.yml +25 -0
  50. langgraph_checkpoint_oceanbase_es-3.0.0/tests/compose-mysql.yml +25 -0
  51. langgraph_checkpoint_oceanbase_es-3.0.0/tests/conftest.py +59 -0
  52. langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/conftest.py +1 -0
  53. langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/run_standalone.py +438 -0
  54. langgraph_checkpoint_oceanbase_es-3.0.0/tests/oceanbase/test_oceanbase.py +561 -0
  55. langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_async.py +590 -0
  56. langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_async_store.py +588 -0
  57. langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_store.py +362 -0
  58. langgraph_checkpoint_oceanbase_es-3.0.0/tests/test_sync.py +461 -0
  59. langgraph_checkpoint_oceanbase_es-3.0.0/uv.lock +1428 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "permissions": {
3
+ "allow": [
4
+ "Bash(uv build *)"
5
+ ]
6
+ }
7
+ }
@@ -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,3 @@
1
+ .mypy_cache/
2
+ __pycache__/
3
+ .idea/
@@ -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
+ ```