mirror of
https://github.com/langchain-ai/langgraph.git
synced 2026-09-29 13:05:15 +02:00
Compare commits
78
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
07b33185ea | ||
|
|
7daa3ab49d | ||
|
|
e868c3ccfd | ||
|
|
bdb85b5aa8 | ||
|
|
1211af45b1 | ||
|
|
1afaca35a0 | ||
|
|
49cce0ca85 | ||
|
|
19273fa88b | ||
|
|
ed384f3a12 | ||
|
|
aa742fb31e | ||
|
|
b58044ac7a | ||
|
|
daa514a988 | ||
|
|
022043a679 | ||
|
|
d7b99cc3ab | ||
|
|
b19edd783b | ||
|
|
c81c13533e | ||
|
|
448a763779 | ||
|
|
230927fb3a | ||
|
|
e539ac122f | ||
|
|
ff4529380d | ||
|
|
c0b884e6d8 | ||
|
|
3299a1f563 | ||
|
|
0199b519e1 | ||
|
|
81bf17b231 | ||
|
|
11738d83db | ||
|
|
1983e60971 | ||
|
|
d07198a53c | ||
|
|
c0a13bb22d | ||
|
|
7bfee11ad5 | ||
|
|
eae02c622d | ||
|
|
bbd6e2da0b | ||
|
|
b7bcf0083c | ||
|
|
7815573c76 | ||
|
|
0cf2f960f6 | ||
|
|
bd1f031ac0 | ||
|
|
d80317dd6c | ||
|
|
394c109737 | ||
|
|
0c1a062f88 | ||
|
|
4b29b60d13 | ||
|
|
59738d1550 | ||
|
|
2efb0073a5 | ||
|
|
408e964501 | ||
|
|
11ee185999 | ||
|
|
d5f4b2aa96 | ||
|
|
5a77be5e8b | ||
|
|
bdb8a9c7a4 | ||
|
|
38031739e5 | ||
|
|
f09cfe8ffc | ||
|
|
837212b969 | ||
|
|
70918557ca | ||
|
|
1e44bda48f | ||
|
|
644815f9e5 | ||
|
|
7d6b5790ba | ||
|
|
d56666f7fb | ||
|
|
6a2822d3c7 | ||
|
|
fde3068970 | ||
|
|
f55e77274d | ||
|
|
a90ab44358 | ||
|
|
ea5f9cc9fb | ||
|
|
36a505ac65 | ||
|
|
d569e18f4b | ||
|
|
f22af6248c | ||
|
|
658541c496 | ||
|
|
fb3d5f0399 | ||
|
|
01521c1b1c | ||
|
|
52d9281005 | ||
|
|
cd62febcfa | ||
|
|
26a92d670c | ||
|
|
4ea0cac0a4 | ||
|
|
2cac3c0932 | ||
|
|
b2af47da46 | ||
|
|
f223c6d6f4 | ||
|
|
e7f05cb67c | ||
|
|
7efdf04209 | ||
|
|
fa36da7e88 | ||
|
|
5efb3d2d87 | ||
|
|
a43147ee57 | ||
|
|
b84734d62f |
@@ -41,7 +41,7 @@ def test(config: pathlib.Path, port: int, tag: str, verbose: bool):
|
|||||||
)
|
)
|
||||||
|
|
||||||
# Compose up with wait (implies detach), similar to `langgraph up --wait`
|
# Compose up with wait (implies detach), similar to `langgraph up --wait`
|
||||||
args_up = [*args, "up", "--remove-orphans", "--wait"]
|
args_up = [*args, "up", "--remove-orphans", "--wait", "--wait-timeout", "180"]
|
||||||
|
|
||||||
compose_cmd = ["docker", "compose"]
|
compose_cmd = ["docker", "compose"]
|
||||||
if capabilities.compose_type == "standalone":
|
if capabilities.compose_type == "standalone":
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: libs/cli
|
working-directory: libs/cli
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
if: github.event_name != 'workflow_dispatch'
|
if: github.event_name != 'workflow_dispatch'
|
||||||
@@ -71,7 +71,7 @@ jobs:
|
|||||||
if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi
|
if [ -f ../.env ]; then echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> ../.env; fi
|
||||||
# Run the integration test using the built tag
|
# Run the integration test using the built tag
|
||||||
REPO_ROOT=$(git rev-parse --show-toplevel)
|
REPO_ROOT=$(git rev-parse --show-toplevel)
|
||||||
timeout 60 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}
|
timeout --kill-after=30 300 python "$REPO_ROOT/.github/scripts/run_langgraph_cli_test.py" -t ${{ matrix.example.tag }}
|
||||||
|
|
||||||
- name: Build JS service
|
- name: Build JS service
|
||||||
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
||||||
@@ -98,7 +98,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp apps/agent/.env.example apps/agent/.env
|
cp apps/agent/.env.example apps/agent/.env
|
||||||
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env
|
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> apps/agent/.env
|
||||||
timeout 60 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
|
timeout --kill-after=30 300 python ../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-g -c apps/agent/langgraph.json
|
||||||
|
|
||||||
- name: Build prerelease reqs service
|
- name: Build prerelease reqs service
|
||||||
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
||||||
@@ -113,11 +113,11 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp ../.env.example .env
|
cp ../.env.example .env
|
||||||
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
||||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
|
timeout --kill-after=30 300 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-h
|
||||||
echo "Finished starting up langgraph-test-h"
|
echo "Finished starting up langgraph-test-h"
|
||||||
LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);")
|
LANGGRAPH_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langgraph'); print(v);")
|
||||||
if [ "$LANGGRAPH_VERSION" != "1.1.5" ]; then
|
if [ "$LANGGRAPH_VERSION" != "1.2.6" ]; then
|
||||||
echo "LANGGRAPH_VERSION != 1.1.5; $LANGGRAPH_VERSION"
|
echo "LANGGRAPH_VERSION != 1.2.6; $LANGGRAPH_VERSION"
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
|
LANGCHAIN_OPENAI_VERSION=$(docker run --rm --entrypoint "" langgraph-test-h python -c "import sys; from importlib.metadata import version; v = version('langchain-openai'); print(v);")
|
||||||
@@ -150,7 +150,7 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
||||||
timeout 60 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-simple
|
timeout --kill-after=30 300 python ../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-simple
|
||||||
|
|
||||||
- name: Build uv monorepo service
|
- name: Build uv monorepo service
|
||||||
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
if: ${{ (steps.changed-files.outputs.all || github.event_name == 'workflow_dispatch') &&matrix.example.name == 'A' }}
|
||||||
@@ -165,4 +165,4 @@ jobs:
|
|||||||
run: |
|
run: |
|
||||||
cp .env.example .env
|
cp .env.example .env
|
||||||
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
echo "LANGSMITH_API_KEY=${{ secrets.LANGSMITH_API_KEY }}" >> .env
|
||||||
timeout 60 python ../../../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-monorepo
|
timeout --kill-after=30 300 python ../../../../../../.github/scripts/run_langgraph_cli_test.py -t langgraph-test-uv-monorepo
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
- "3.12"
|
- "3.12"
|
||||||
name: "lint #${{ matrix.python-version }}"
|
name: "lint #${{ matrix.python-version }}"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Get changed files
|
- name: Get changed files
|
||||||
id: changed-files
|
id: changed-files
|
||||||
if: github.event_name != 'workflow_dispatch'
|
if: github.event_name != 'workflow_dispatch'
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
env:
|
env:
|
||||||
HAS_LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY != '' }}
|
HAS_LANGSMITH_API_KEY: ${{ secrets.LANGSMITH_API_KEY != '' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
working-directory: libs/sdk-py
|
working-directory: libs/sdk-py
|
||||||
|
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
|
|
||||||
name: "test #${{ matrix.python-version }}"
|
name: "test #${{ matrix.python-version }}"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
with:
|
with:
|
||||||
@@ -33,7 +33,7 @@ jobs:
|
|||||||
cache-suffix: test-${{ inputs.working-directory }}
|
cache-suffix: test-${{ inputs.working-directory }}
|
||||||
working-directory: ${{ inputs.working-directory }}
|
working-directory: ${{ inputs.working-directory }}
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
working-directory: libs/langgraph
|
working-directory: libs/langgraph
|
||||||
name: "test #${{ matrix.python-version }}"
|
name: "test #${{ matrix.python-version }}"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
with:
|
with:
|
||||||
@@ -31,7 +31,7 @@ jobs:
|
|||||||
cache-suffix: "test-langgraph"
|
cache-suffix: "test-langgraph"
|
||||||
working-directory: libs/langgraph
|
working-directory: libs/langgraph
|
||||||
- name: Login to Docker Hub
|
- name: Login to Docker Hub
|
||||||
uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4
|
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
|
||||||
if: ${{ !github.event.pull_request.head.repo.fork }}
|
if: ${{ !github.event.pull_request.head.repo.fork }}
|
||||||
with:
|
with:
|
||||||
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
username: ${{ secrets.DOCKERHUB_USERNAME }}
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ jobs:
|
|||||||
version: ${{ steps.check-version.outputs.version }}
|
version: ${{ steps.check-version.outputs.version }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
- name: Set up Python ${{ env.PYTHON_VERSION }}
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
@@ -74,7 +74,7 @@ jobs:
|
|||||||
id-token: write
|
id-token: write
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||||
with:
|
with:
|
||||||
@@ -82,7 +82,7 @@ jobs:
|
|||||||
path: ${{ inputs.working-directory }}/dist/
|
path: ${{ inputs.working-directory }}/dist/
|
||||||
|
|
||||||
- name: Publish to test PyPI
|
- name: Publish to test PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
||||||
with:
|
with:
|
||||||
packages-dir: ${{ inputs.working-directory }}/dist/
|
packages-dir: ${{ inputs.working-directory }}/dist/
|
||||||
verbose: true
|
verbose: true
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: libs/langgraph
|
working-directory: libs/langgraph
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
|
- run: SHA=$(git rev-parse HEAD) && echo "SHA=$SHA" >> $GITHUB_ENV
|
||||||
- name: Set up Python 3.11
|
- name: Set up Python 3.11
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ jobs:
|
|||||||
run:
|
run:
|
||||||
working-directory: libs/langgraph
|
working-directory: libs/langgraph
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- id: files
|
- id: files
|
||||||
name: Get changed files
|
name: Get changed files
|
||||||
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
|
uses: Ana06/get-changed-files@25f79e676e7ea1868813e21465014798211fad8c # v2.3.0
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ jobs:
|
|||||||
deps: ${{ steps.filter.outputs.deps || 'true' }}
|
deps: ${{ steps.filter.outputs.deps || 'true' }}
|
||||||
sdk_py: ${{ steps.filter.outputs.sdk_py || 'true' }}
|
sdk_py: ${{ steps.filter.outputs.sdk_py || 'true' }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- uses: dorny/paths-filter@fbd0ab8f3e69293af611ebaee6363fc25e6d187d # v4
|
- uses: dorny/paths-filter@ceb8a2b8f2d89434be7ff52d3de7ec3738c5cc9d # v4
|
||||||
if: github.event_name != 'workflow_dispatch'
|
if: github.event_name != 'workflow_dispatch'
|
||||||
id: filter
|
id: filter
|
||||||
with:
|
with:
|
||||||
@@ -112,9 +112,9 @@ jobs:
|
|||||||
name: "Check SDK methods matching"
|
name: "Check SDK methods matching"
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||||
with:
|
with:
|
||||||
python-version: "3.11"
|
python-version: "3.11"
|
||||||
- name: Run check_sdk_methods script
|
- name: Run check_sdk_methods script
|
||||||
@@ -130,7 +130,7 @@ jobs:
|
|||||||
python-version:
|
python-version:
|
||||||
- "3.13"
|
- "3.13"
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
- name: Set up Python ${{ matrix.python-version }}
|
- name: Set up Python ${{ matrix.python-version }}
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
with:
|
with:
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ on:
|
|||||||
paths:
|
paths:
|
||||||
- 'docs/**'
|
- 'docs/**'
|
||||||
- '.github/workflows/deploy-redirects.yml'
|
- '.github/workflows/deploy-redirects.yml'
|
||||||
|
# llms.txt is fetched from docs.langchain.com at build time, so redeploy on a
|
||||||
|
# schedule to pick up docs changes that never touch this repo.
|
||||||
|
schedule:
|
||||||
|
- cron: '17 6 * * 1'
|
||||||
workflow_dispatch:
|
workflow_dispatch:
|
||||||
|
|
||||||
permissions:
|
permissions:
|
||||||
@@ -26,10 +30,10 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout
|
- name: Checkout
|
||||||
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Setup Python
|
- name: Setup Python
|
||||||
uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0
|
uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0
|
||||||
with:
|
with:
|
||||||
python-version: '3.11'
|
python-version: '3.11'
|
||||||
|
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ jobs:
|
|||||||
tag: ${{ steps.check-version.outputs.tag }}
|
tag: ${{ steps.check-version.outputs.tag }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
@@ -87,7 +87,7 @@ jobs:
|
|||||||
outputs:
|
outputs:
|
||||||
release-body: ${{ steps.generate-release-body.outputs.release-body }}
|
release-body: ${{ steps.generate-release-body.outputs.release-body }}
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
with:
|
with:
|
||||||
repository: langchain-ai/langgraph
|
repository: langchain-ai/langgraph
|
||||||
path: langgraph
|
path: langgraph
|
||||||
@@ -158,7 +158,7 @@ jobs:
|
|||||||
- test-pypi-publish
|
- test-pypi-publish
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
# We explicitly *don't* set up caching here. This ensures our tests are
|
# We explicitly *don't* set up caching here. This ensures our tests are
|
||||||
# maximally sensitive to catching breakage.
|
# maximally sensitive to catching breakage.
|
||||||
@@ -262,7 +262,7 @@ jobs:
|
|||||||
working-directory: ${{ inputs.working-directory }}
|
working-directory: ${{ inputs.working-directory }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
@@ -278,7 +278,7 @@ jobs:
|
|||||||
path: ${{ inputs.working-directory }}/dist/
|
path: ${{ inputs.working-directory }}/dist/
|
||||||
|
|
||||||
- name: Publish package distributions to PyPI
|
- name: Publish package distributions to PyPI
|
||||||
uses: pypa/gh-action-pypi-publish@cef221092ed1bacb1cc03d23a2d87d1d172e277b # release/v1
|
uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # release/v1
|
||||||
with:
|
with:
|
||||||
packages-dir: ${{ inputs.working-directory }}/dist/
|
packages-dir: ${{ inputs.working-directory }}/dist/
|
||||||
verbose: true
|
verbose: true
|
||||||
@@ -304,7 +304,7 @@ jobs:
|
|||||||
working-directory: ${{ inputs.working-directory }}
|
working-directory: ${{ inputs.working-directory }}
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ jobs:
|
|||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
|
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
|
||||||
|
|
||||||
- name: Set up uv
|
- name: Set up uv
|
||||||
uses: ./.github/actions/uv_setup
|
uses: ./.github/actions/uv_setup
|
||||||
|
|||||||
@@ -76,7 +76,12 @@ __pypackages__/
|
|||||||
|
|
||||||
# Environments
|
# Environments
|
||||||
.env
|
.env
|
||||||
|
.env.*
|
||||||
.envrc
|
.envrc
|
||||||
|
*.crt
|
||||||
|
*.key
|
||||||
|
*.pem
|
||||||
|
credentials.json
|
||||||
.venv
|
.venv
|
||||||
.venvs
|
.venvs
|
||||||
env/
|
env/
|
||||||
@@ -98,6 +103,7 @@ dmypy.json
|
|||||||
|
|
||||||
.vercel
|
.vercel
|
||||||
.turbo
|
.turbo
|
||||||
|
node_modules/
|
||||||
.editorconfig
|
.editorconfig
|
||||||
.scratch
|
.scratch
|
||||||
.worktrees/
|
.worktrees/
|
||||||
|
|||||||
@@ -2,6 +2,14 @@
|
|||||||
|
|
||||||
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
|
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
|
||||||
|
|
||||||
|
<corridor>
|
||||||
|
|
||||||
|
## Corridor security analysis
|
||||||
|
|
||||||
|
When Corridor's `analyzePlan` tool is available, create a plan and use the tool to analyze it before generating or modifying code. Apply the resulting security guidance before writing code.
|
||||||
|
|
||||||
|
</corridor>
|
||||||
|
|
||||||
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
|
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
|
||||||
|
|
||||||
- `make format` – run code formatters
|
- `make format` – run code formatters
|
||||||
|
|||||||
@@ -1,57 +0,0 @@
|
|||||||
# AGENTS Instructions
|
|
||||||
|
|
||||||
This repository is a monorepo. Each library lives in a subdirectory under `libs/`.
|
|
||||||
|
|
||||||
When you modify code in any library, run the following commands in that library's directory before creating a pull request:
|
|
||||||
|
|
||||||
- `make format` – run code formatters
|
|
||||||
- `make lint` – run the linter
|
|
||||||
- `make test` – execute the test suite
|
|
||||||
|
|
||||||
To run a particular test file or to pass additional pytest options you can specify the `TEST` variable:
|
|
||||||
|
|
||||||
```
|
|
||||||
TEST=path/to/test.py make test
|
|
||||||
```
|
|
||||||
|
|
||||||
Other pytest arguments can also be supplied inside the `TEST` variable.
|
|
||||||
|
|
||||||
## Libraries
|
|
||||||
|
|
||||||
The repository contains several Python and JavaScript/TypeScript libraries.
|
|
||||||
Below is a high-level overview:
|
|
||||||
|
|
||||||
- **checkpoint** – base interfaces for LangGraph checkpointers.
|
|
||||||
- **checkpoint-postgres** – Postgres implementation of the checkpoint saver.
|
|
||||||
- **checkpoint-sqlite** – SQLite implementation of the checkpoint saver.
|
|
||||||
- **cli** – official command-line interface for LangGraph.
|
|
||||||
- **langgraph** – core framework for building stateful, multi-actor agents.
|
|
||||||
- **prebuilt** – high-level APIs for creating and running agents and tools.
|
|
||||||
- **sdk-js** – JS/TS SDK for interacting with the LangGraph REST API.
|
|
||||||
- **sdk-py** – Python SDK for the LangGraph Server API.
|
|
||||||
|
|
||||||
### Dependency map
|
|
||||||
|
|
||||||
The diagram below lists downstream libraries for each production dependency as
|
|
||||||
declared in that library's `pyproject.toml` (or `package.json`).
|
|
||||||
|
|
||||||
```text
|
|
||||||
checkpoint
|
|
||||||
├── checkpoint-postgres
|
|
||||||
├── checkpoint-sqlite
|
|
||||||
├── prebuilt
|
|
||||||
└── langgraph
|
|
||||||
|
|
||||||
prebuilt
|
|
||||||
└── langgraph
|
|
||||||
|
|
||||||
sdk-py
|
|
||||||
├── langgraph
|
|
||||||
└── cli
|
|
||||||
|
|
||||||
sdk-js (standalone)
|
|
||||||
```
|
|
||||||
|
|
||||||
Changes to a library may impact all of its dependents shown above.
|
|
||||||
|
|
||||||
- Do NOT use Sphinx-style double backtick formatting (` ``code`` `). Use single backticks (`` `code` ``) for inline code references in docstrings and comments.
|
|
||||||
@@ -12,13 +12,26 @@ which is SEO-friendly and treated similarly to 301 redirects by Google.
|
|||||||
To add new redirects, simply edit redirects.json and re-run this script.
|
To add new redirects, simply edit redirects.json and re-run this script.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import http.client
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
# Default fallback URL for any path not in the redirect map
|
# Default fallback URL for any path not in the redirect map
|
||||||
DEFAULT_REDIRECT = "https://docs.langchain.com/oss/python/langgraph/overview"
|
DEFAULT_REDIRECT = "https://docs.langchain.com/oss/python/langgraph/overview"
|
||||||
|
|
||||||
|
# The docs site regenerates this index on every deploy, so fetching it here
|
||||||
|
# keeps the published llms.txt from drifting. The URL is a hardcoded constant,
|
||||||
|
# never built from input, and both it and the post-redirect URL are checked
|
||||||
|
# against ALLOWED_LLMS_HOST before anything is read.
|
||||||
|
CANONICAL_LLMS_URL = "https://docs.langchain.com/oss/python/langgraph/llms.txt"
|
||||||
|
ALLOWED_LLMS_HOST = "docs.langchain.com"
|
||||||
|
LLMS_FETCH_TIMEOUT = 30
|
||||||
|
LLMS_MAX_BYTES = 1_000_000
|
||||||
|
|
||||||
HTML_TEMPLATE = """<!doctype html>
|
HTML_TEMPLATE = """<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
@@ -75,6 +88,64 @@ CATCHALL_404_TEMPLATE = """<!doctype html>
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def is_allowed_llms_url(url):
|
||||||
|
"""Return True if url is HTTPS on the one host we accept content from."""
|
||||||
|
parsed = urllib.parse.urlsplit(url)
|
||||||
|
return parsed.scheme == "https" and parsed.hostname == ALLOWED_LLMS_HOST
|
||||||
|
|
||||||
|
|
||||||
|
def fetch_canonical_llms_txt():
|
||||||
|
"""Return the published LangGraph index, or None if it cannot be used.
|
||||||
|
|
||||||
|
Returning None leaves the caller on the committed docs/llms.txt, so a
|
||||||
|
docs.langchain.com outage degrades to a stale file rather than a broken
|
||||||
|
deploy or a published error page.
|
||||||
|
"""
|
||||||
|
if not is_allowed_llms_url(CANONICAL_LLMS_URL):
|
||||||
|
print(f"Refusing to fetch {CANONICAL_LLMS_URL}: host not allowed")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen( # noqa: S310 - constant, allowlisted URL
|
||||||
|
CANONICAL_LLMS_URL, timeout=LLMS_FETCH_TIMEOUT
|
||||||
|
) as response:
|
||||||
|
# urlopen follows redirects, so re-check where it actually landed.
|
||||||
|
if not is_allowed_llms_url(response.url):
|
||||||
|
print(f"Refusing {CANONICAL_LLMS_URL}: redirected to {response.url}")
|
||||||
|
return None
|
||||||
|
body = response.read(LLMS_MAX_BYTES + 1)
|
||||||
|
# A connection dropped mid-body raises http.client.IncompleteRead, which
|
||||||
|
# descends from HTTPException rather than OSError, so catching only the
|
||||||
|
# urllib and OS errors would let it escape and fail the whole deploy.
|
||||||
|
except (
|
||||||
|
urllib.error.URLError,
|
||||||
|
http.client.HTTPException,
|
||||||
|
TimeoutError,
|
||||||
|
OSError,
|
||||||
|
) as exc:
|
||||||
|
print(f"Could not fetch {CANONICAL_LLMS_URL}: {type(exc).__name__}: {exc}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if len(body) > LLMS_MAX_BYTES:
|
||||||
|
print(f"Refusing {CANONICAL_LLMS_URL}: larger than {LLMS_MAX_BYTES} bytes")
|
||||||
|
return None
|
||||||
|
|
||||||
|
try:
|
||||||
|
text = body.decode("utf-8")
|
||||||
|
except UnicodeDecodeError as exc:
|
||||||
|
print(f"Refusing {CANONICAL_LLMS_URL}: not valid UTF-8: {exc}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
# An index opens with a markdown heading and links to the docs site. A
|
||||||
|
# body that does not is an error page or a truncated response, not content
|
||||||
|
# worth publishing.
|
||||||
|
if not text.startswith("# ") or f"https://{ALLOWED_LLMS_HOST}/" not in text:
|
||||||
|
print(f"Refusing {CANONICAL_LLMS_URL}: does not look like an llms.txt index")
|
||||||
|
return None
|
||||||
|
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
def generate_redirects():
|
def generate_redirects():
|
||||||
script_dir = Path(__file__).parent
|
script_dir = Path(__file__).parent
|
||||||
output_dir = script_dir / "_site"
|
output_dir = script_dir / "_site"
|
||||||
@@ -126,14 +197,19 @@ def generate_redirects():
|
|||||||
catchall_404.write_text(CATCHALL_404_TEMPLATE.format(default_url=DEFAULT_REDIRECT))
|
catchall_404.write_text(CATCHALL_404_TEMPLATE.format(default_url=DEFAULT_REDIRECT))
|
||||||
print(f"Created: {catchall_404}")
|
print(f"Created: {catchall_404}")
|
||||||
|
|
||||||
# Copy static files (like llms.txt) that can't be redirected via HTML
|
# llms.txt can't be redirected via HTML, so publish the docs site's own
|
||||||
static_files = ["llms.txt"]
|
# generated index. The committed copy is only a fallback.
|
||||||
for static_file in static_files:
|
llms_txt = fetch_canonical_llms_txt()
|
||||||
src = script_dir / static_file
|
if llms_txt is not None:
|
||||||
|
(output_dir / "llms.txt").write_text(llms_txt)
|
||||||
|
print(f"Fetched: {output_dir / 'llms.txt'} (from {CANONICAL_LLMS_URL})")
|
||||||
|
else:
|
||||||
|
src = script_dir / "llms.txt"
|
||||||
if src.exists():
|
if src.exists():
|
||||||
dst = output_dir / static_file
|
(output_dir / "llms.txt").write_text(src.read_text())
|
||||||
dst.write_text(src.read_text())
|
print(f"Copied: {output_dir / 'llms.txt'} (fallback, may be stale)")
|
||||||
print(f"Copied: {dst}")
|
else:
|
||||||
|
print("No llms.txt fetched and no committed fallback; skipping")
|
||||||
|
|
||||||
print(f"\nGenerated {len(redirects)} redirect files in {output_dir}")
|
print(f"\nGenerated {len(redirects)} redirect files in {output_dir}")
|
||||||
|
|
||||||
|
|||||||
+46
-32
@@ -1,35 +1,49 @@
|
|||||||
# LangGraph
|
# Docs by LangChain: LangGraph (Python)
|
||||||
|
|
||||||
LangGraph documentation has moved to docs.langchain.com.
|
> Markdown index of the LangGraph (Python) documentation.
|
||||||
|
|
||||||
## Overview
|
## LangGraph (Python)
|
||||||
|
|
||||||
- [LangGraph Overview](https://docs.langchain.com/oss/python/langgraph/overview): Introduction to LangGraph, a library for building stateful, multi-actor applications with LLMs.
|
- [Memory](https://docs.langchain.com/oss/python/langgraph/add-memory.md)
|
||||||
- [Why LangGraph?](https://docs.langchain.com/oss/python/langgraph/why-langgraph): Motivation for LangGraph and its key features.
|
- [Build a custom RAG agent with LangGraph](https://docs.langchain.com/oss/python/langgraph/agentic-rag.md)
|
||||||
|
- [Application structure](https://docs.langchain.com/oss/python/langgraph/application-structure.md)
|
||||||
## Core Concepts
|
- [Backward compatibility](https://docs.langchain.com/oss/python/langgraph/backward-compatibility.md)
|
||||||
|
- [Case studies](https://docs.langchain.com/oss/python/langgraph/case-studies.md)
|
||||||
- [Graph API](https://docs.langchain.com/oss/python/langgraph/graph-api): Learn how to define state, create nodes, and connect them with edges.
|
- [Changelog](https://docs.langchain.com/oss/python/langgraph/changelog-js.md)
|
||||||
- [Streaming](https://docs.langchain.com/oss/python/langgraph/streaming): Stream outputs from your graph for better UX.
|
- [Changelog](https://docs.langchain.com/oss/python/langgraph/changelog-py.md)
|
||||||
- [Persistence](https://docs.langchain.com/oss/python/langgraph/persistence): Add memory and checkpointing to your graphs.
|
- [Checkpointers](https://docs.langchain.com/oss/python/langgraph/checkpointers.md)
|
||||||
- [Add Memory](https://docs.langchain.com/oss/python/langgraph/add-memory): Implement short-term and long-term memory.
|
- [Choosing between Graph and Functional APIs](https://docs.langchain.com/oss/python/langgraph/choosing-apis.md)
|
||||||
- [Workflows & Agents](https://docs.langchain.com/oss/python/langgraph/workflows-agents): Build agents and workflows with LangGraph.
|
- [Deployment](https://docs.langchain.com/oss/python/langgraph/deploy.md)
|
||||||
|
- [GRAPH_RECURSION_LIMIT](https://docs.langchain.com/oss/python/langgraph/errors/GRAPH_RECURSION_LIMIT.md)
|
||||||
## How-To Guides
|
- [INVALID_CHAT_HISTORY](https://docs.langchain.com/oss/python/langgraph/errors/INVALID_CHAT_HISTORY.md)
|
||||||
|
- [INVALID_CONCURRENT_GRAPH_UPDATE](https://docs.langchain.com/oss/python/langgraph/errors/INVALID_CONCURRENT_GRAPH_UPDATE.md)
|
||||||
- [Use Subgraphs](https://docs.langchain.com/oss/python/langgraph/use-subgraphs): Compose graphs using subgraphs.
|
- [INVALID_GRAPH_NODE_RETURN_VALUE](https://docs.langchain.com/oss/python/langgraph/errors/INVALID_GRAPH_NODE_RETURN_VALUE.md)
|
||||||
- [Observability](https://docs.langchain.com/oss/python/langgraph/observability): Add tracing and debugging to your graphs.
|
- [MISSING_CHECKPOINTER](https://docs.langchain.com/oss/python/langgraph/errors/MISSING_CHECKPOINTER.md)
|
||||||
- [Common Errors](https://docs.langchain.com/oss/python/langgraph/common-errors): Troubleshoot common LangGraph errors.
|
- [MULTIPLE_SUBGRAPHS](https://docs.langchain.com/oss/python/langgraph/errors/MULTIPLE_SUBGRAPHS.md)
|
||||||
|
- [Event streaming](https://docs.langchain.com/oss/python/langgraph/event-streaming.md)
|
||||||
## Tutorials
|
- [Fault tolerance](https://docs.langchain.com/oss/python/langgraph/fault-tolerance.md)
|
||||||
|
- [Custom stream channels](https://docs.langchain.com/oss/python/langgraph/frontend/custom-stream-channels.md)
|
||||||
- [Agentic RAG](https://docs.langchain.com/oss/python/langgraph/agentic-rag): Build an agentic RAG system with LangGraph.
|
- [Graph execution](https://docs.langchain.com/oss/python/langgraph/frontend/graph-execution.md)
|
||||||
- [SQL Agent](https://docs.langchain.com/oss/python/langgraph/sql-agent): Create a SQL agent with LangGraph.
|
- [Overview](https://docs.langchain.com/oss/python/langgraph/frontend/overview.md)
|
||||||
|
- [Functional API overview](https://docs.langchain.com/oss/python/langgraph/functional-api.md)
|
||||||
## Reference
|
- [Graph API overview](https://docs.langchain.com/oss/python/langgraph/graph-api.md)
|
||||||
|
- [Install LangGraph](https://docs.langchain.com/oss/python/langgraph/install.md)
|
||||||
- [API Reference](https://reference.langchain.com/python/langgraph/): Complete API documentation for LangGraph.
|
- [Interrupts](https://docs.langchain.com/oss/python/langgraph/interrupts.md)
|
||||||
|
- [Run a local server](https://docs.langchain.com/oss/python/langgraph/local-server.md)
|
||||||
## LangGraph Platform
|
- [LangSmith Observability](https://docs.langchain.com/oss/python/langgraph/observability.md)
|
||||||
|
- [LangGraph overview](https://docs.langchain.com/oss/python/langgraph/overview.md)
|
||||||
For deploying LangGraph applications in production, see the [LangSmith documentation](https://docs.langchain.com/langsmith/agent-server).
|
- [Persistence](https://docs.langchain.com/oss/python/langgraph/persistence.md)
|
||||||
|
- [LangGraph runtime](https://docs.langchain.com/oss/python/langgraph/pregel.md)
|
||||||
|
- [Quickstart](https://docs.langchain.com/oss/python/langgraph/quickstart.md)
|
||||||
|
- [Build a custom SQL agent](https://docs.langchain.com/oss/python/langgraph/sql-agent.md)
|
||||||
|
- [Stores](https://docs.langchain.com/oss/python/langgraph/stores.md)
|
||||||
|
- [Streaming](https://docs.langchain.com/oss/python/langgraph/streaming.md)
|
||||||
|
- [LangSmith Studio](https://docs.langchain.com/oss/python/langgraph/studio.md)
|
||||||
|
- [Test](https://docs.langchain.com/oss/python/langgraph/test.md)
|
||||||
|
- [Thinking in LangGraph](https://docs.langchain.com/oss/python/langgraph/thinking-in-langgraph.md)
|
||||||
|
- [Agent Chat UI](https://docs.langchain.com/oss/python/langgraph/ui.md)
|
||||||
|
- [Use the functional API](https://docs.langchain.com/oss/python/langgraph/use-functional-api.md)
|
||||||
|
- [Use the graph API](https://docs.langchain.com/oss/python/langgraph/use-graph-api.md)
|
||||||
|
- [Subgraphs](https://docs.langchain.com/oss/python/langgraph/use-subgraphs.md)
|
||||||
|
- [Use time-travel](https://docs.langchain.com/oss/python/langgraph/use-time-travel.md)
|
||||||
|
- [Workflows and agents](https://docs.langchain.com/oss/python/langgraph/workflows-agents.md)
|
||||||
|
|||||||
+73
-13
@@ -6,9 +6,12 @@ import traceback
|
|||||||
from collections.abc import Callable
|
from collections.abc import Callable
|
||||||
from uuid import uuid4
|
from uuid import uuid4
|
||||||
|
|
||||||
from langgraph.checkpoint.base import BaseCheckpointSaver
|
from langgraph.checkpoint.base import BaseCheckpointSaver, Checkpoint
|
||||||
|
from langgraph.checkpoint.base.id import uuid6
|
||||||
|
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
||||||
|
|
||||||
from langgraph.checkpoint.conformance.spec._delta_fixtures import build_delta_chain
|
from langgraph.checkpoint.conformance.spec._delta_fixtures import build_delta_chain
|
||||||
|
from langgraph.checkpoint.conformance.test_utils import generate_metadata
|
||||||
|
|
||||||
|
|
||||||
async def test_history_returns_writes_oldest_first(
|
async def test_history_returns_writes_oldest_first(
|
||||||
@@ -48,8 +51,6 @@ async def test_history_seed_is_nearest_snapshot(
|
|||||||
result = await saver.aget_delta_channel_history(config=head, channels=["ch"])
|
result = await saver.aget_delta_channel_history(config=head, channels=["ch"])
|
||||||
assert "seed" in result["ch"], "Expected seed from snapshot at step 3"
|
assert "seed" in result["ch"], "Expected seed from snapshot at step 3"
|
||||||
seed = result["ch"]["seed"]
|
seed = result["ch"]["seed"]
|
||||||
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
|
||||||
|
|
||||||
actual_value = seed.value if isinstance(seed, _DeltaSnapshot) else seed
|
actual_value = seed.value if isinstance(seed, _DeltaSnapshot) else seed
|
||||||
assert actual_value == 3, f"Expected seed value 3 (step 3), got {actual_value}"
|
assert actual_value == 3, f"Expected seed value 3 (step 3), got {actual_value}"
|
||||||
writes = result["ch"]["writes"]
|
writes = result["ch"]["writes"]
|
||||||
@@ -81,11 +82,6 @@ async def test_history_multi_channel(
|
|||||||
tid = str(uuid4())
|
tid = str(uuid4())
|
||||||
configs: list = []
|
configs: list = []
|
||||||
parent_cfg = None
|
parent_cfg = None
|
||||||
from langgraph.checkpoint.base import Checkpoint
|
|
||||||
from langgraph.checkpoint.base.id import uuid6
|
|
||||||
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
|
||||||
|
|
||||||
from langgraph.checkpoint.conformance.test_utils import generate_metadata
|
|
||||||
|
|
||||||
for step in range(5):
|
for step in range(5):
|
||||||
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
|
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
|
||||||
@@ -161,11 +157,6 @@ async def test_history_migration_plain_value_as_seed(
|
|||||||
channel_values[ch] (not a _DeltaSnapshot). The walk should treat it as the
|
channel_values[ch] (not a _DeltaSnapshot). The walk should treat it as the
|
||||||
seed and terminate there.
|
seed and terminate there.
|
||||||
"""
|
"""
|
||||||
from langgraph.checkpoint.base import Checkpoint
|
|
||||||
from langgraph.checkpoint.base.id import uuid6
|
|
||||||
|
|
||||||
from langgraph.checkpoint.conformance.test_utils import generate_metadata
|
|
||||||
|
|
||||||
tid = str(uuid4())
|
tid = str(uuid4())
|
||||||
configs: list = []
|
configs: list = []
|
||||||
parent_cfg = None
|
parent_cfg = None
|
||||||
@@ -208,6 +199,74 @@ async def test_history_migration_plain_value_as_seed(
|
|||||||
assert values == [2], f"Expected [2], got {values}"
|
assert values == [2], f"Expected [2], got {values}"
|
||||||
|
|
||||||
|
|
||||||
|
async def test_history_seed_ancestor_own_writes_are_replayed(
|
||||||
|
saver: BaseCheckpointSaver,
|
||||||
|
) -> None:
|
||||||
|
"""Writes stored AT the seed ancestor must be included in `writes`.
|
||||||
|
|
||||||
|
A stored value is the state ENTERING its checkpoint; the writes stored
|
||||||
|
under that same checkpoint are what produced its child and are therefore
|
||||||
|
NOT subsumed by it. Only writes at ancestors OLDER than the seed are
|
||||||
|
subsumed, and the walk terminates before reaching them.
|
||||||
|
|
||||||
|
This holds for plain-value seeds (migration from a pre-delta channel type)
|
||||||
|
exactly as it does for `_DeltaSnapshot` seeds. Skipping the seed
|
||||||
|
ancestor's own writes silently drops the first post-migration write.
|
||||||
|
"""
|
||||||
|
tid = str(uuid4())
|
||||||
|
configs: list = []
|
||||||
|
parent_cfg = None
|
||||||
|
|
||||||
|
# Each step's write is labelled by the role it plays, so the assertion
|
||||||
|
# below reads directly rather than by step index.
|
||||||
|
writes_by_step = {
|
||||||
|
0: "older-than-seed", # subsumed by the value stored at step 1
|
||||||
|
1: "at-seed", # the seed's own write, produced step 2
|
||||||
|
2: "after-seed", # delta-era write on the path to the head
|
||||||
|
3: "pending-at-head", # pending for the next step, never replayed
|
||||||
|
}
|
||||||
|
# Steps 0 and 1 store a plain value; 1 is the nearest, so it is the seed.
|
||||||
|
values_by_step = {0: [10], 1: [10, 20]}
|
||||||
|
|
||||||
|
for step in range(4):
|
||||||
|
config = {"configurable": {"thread_id": tid, "checkpoint_ns": ""}}
|
||||||
|
if parent_cfg:
|
||||||
|
config["configurable"]["checkpoint_id"] = parent_cfg["configurable"][
|
||||||
|
"checkpoint_id"
|
||||||
|
]
|
||||||
|
cv: dict = {}
|
||||||
|
cvs: dict = {}
|
||||||
|
if step in values_by_step:
|
||||||
|
cv["ch"] = values_by_step[step]
|
||||||
|
cvs["ch"] = step + 1
|
||||||
|
cp = Checkpoint(
|
||||||
|
v=1,
|
||||||
|
id=str(uuid6(clock_seq=-1)),
|
||||||
|
ts="",
|
||||||
|
channel_values=cv,
|
||||||
|
channel_versions=cvs,
|
||||||
|
versions_seen={},
|
||||||
|
updated_channels=None,
|
||||||
|
)
|
||||||
|
parent_cfg = await saver.aput(config, cp, generate_metadata(step=step), cvs)
|
||||||
|
configs.append(parent_cfg)
|
||||||
|
await saver.aput_writes(
|
||||||
|
parent_cfg, [("ch", writes_by_step[step])], str(uuid4())
|
||||||
|
)
|
||||||
|
|
||||||
|
head = configs[-1]
|
||||||
|
result = await saver.aget_delta_channel_history(config=head, channels=["ch"])
|
||||||
|
|
||||||
|
assert "seed" in result["ch"], "Expected seed from plain value at step 1"
|
||||||
|
assert result["ch"]["seed"] == [10, 20], (
|
||||||
|
f"Expected nearest plain value [10, 20], got {result['ch']['seed']}"
|
||||||
|
)
|
||||||
|
values = [w[2] for w in result["ch"]["writes"]]
|
||||||
|
assert values == ["at-seed", "after-seed"], (
|
||||||
|
f'Expected ["at-seed", "after-seed"], got {values}'
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
ALL_DELTA_CHANNEL_HISTORY_TESTS = [
|
ALL_DELTA_CHANNEL_HISTORY_TESTS = [
|
||||||
test_history_returns_writes_oldest_first,
|
test_history_returns_writes_oldest_first,
|
||||||
test_history_seed_is_nearest_snapshot,
|
test_history_seed_is_nearest_snapshot,
|
||||||
@@ -216,6 +275,7 @@ ALL_DELTA_CHANNEL_HISTORY_TESTS = [
|
|||||||
test_history_empty_channels_returns_empty,
|
test_history_empty_channels_returns_empty,
|
||||||
test_history_walk_to_root_no_seed,
|
test_history_walk_to_root_no_seed,
|
||||||
test_history_migration_plain_value_as_seed,
|
test_history_migration_plain_value_as_seed,
|
||||||
|
test_history_seed_ancestor_own_writes_are_replayed,
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -58,8 +58,14 @@ lint.select = [
|
|||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
|
"PLC0415", # import-outside-top-level
|
||||||
|
"RUF100", # unused noqa directive
|
||||||
]
|
]
|
||||||
lint.ignore = ["E501", "B008"]
|
lint.ignore = ["E501", "B008"]
|
||||||
|
# PLC0415 (import-outside-top-level) is enforced in tests only. Library code
|
||||||
|
# still has deferred imports that have not been reviewed, so it stays exempt
|
||||||
|
# for now.
|
||||||
|
lint.per-file-ignores = { "langgraph/**" = ["PLC0415"] }
|
||||||
target-version = "py310"
|
target-version = "py310"
|
||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
|
|||||||
Generated
+46
-46
@@ -13,16 +13,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.13.0"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -162,7 +162,7 @@ name = "exceptiongroup"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ 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" }
|
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 = [
|
wheels = [
|
||||||
@@ -247,7 +247,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.4.8"
|
version = "1.5.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
@@ -260,9 +260,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/12/e3/bea6d0080acf183332f24dcd74c208aee5857cf8f783c3fb0bd86027d8fb/langchain_core-1.4.8.tar.gz", hash = "sha256:5bf1f8411077c904182ad8f975943d36adcbf579c4e017b3a118b719229ebf9a", size = 957974, upload-time = "2026-06-18T19:39:23.636Z" }
|
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" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl", hash = "sha256:d84c28b05e3ba8d4271d0827aad5b592ccdaaf986e76768c23503f0a2045e8aa", size = 557416, upload-time = "2026-06-18T19:39:21.902Z" },
|
{ 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" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -279,7 +279,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.1.1"
|
version = "4.2.0"
|
||||||
source = { editable = "../checkpoint" }
|
source = { editable = "../checkpoint" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -809,27 +809,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.20"
|
version = "0.16.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/85/c8e12473c93018f92d19dd988a294202e1c27426c47ec4de53ffb847b8d8/ruff-0.16.5.tar.gz", hash = "sha256:1b88500f9ffbcab3dedb0082c9f9492e91ec3d618aac1236a3e0189938f7040b", size = 4912003, upload-time = "2026-08-27T16:34:18.258Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/b6/77c90a970fe2dae17a723acbd011043ea97c98d7deacccefdc4ba74ec512/ruff-0.16.5-py3-none-linux_armv6l.whl", hash = "sha256:12e5f673e774c35fbb62f288809c7653b73445f8ecec6b6063fd6ea3521aa14b", size = 10011941, upload-time = "2026-08-27T16:33:41.287Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/4b/46/6cf67cf6411885a1d6f7f6d801682f155536a85176d10b605e2ceffed8bd/ruff-0.16.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eda58a5802de40e7ed5b32b64e0b32539338cc6fcd2c78f61e3ad6a0d79f51c3", size = 10204049, upload-time = "2026-08-27T16:33:44.056Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/fd/c8720ca7a090abf0c2fef4abe8a5ef6e5127ed15196d8886ff75a2b370e2/ruff-0.16.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5ae9a7b9a8875131f40f8fe967cc86abf899779efd663cb7ce3d572d01da7eb", size = 9809037, upload-time = "2026-08-27T16:33:46.257Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/45/a684caacdedaca180f52bacccc40bf0789d2c5a7c75f25324853e9eaedb5/ruff-0.16.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b719b0a1f4d59710d283ab2965f621684a108a9e41da622e3b23f0326cd0025", size = 9964129, upload-time = "2026-08-27T16:33:48.352Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/5d2bcdaca6b5b93d1b4dfc166cd2aebf7680143a1b38a28759df13a94d31/ruff-0.16.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2298f2780ed1be0c5cb1361e32ab7b1467f3cce7dabe101d2210a314f2fe42e9", size = 9821518, upload-time = "2026-08-27T16:33:50.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/ff/011cce29accf9257d5974145b733fc653a37985ed6825413a3987cefbfe0/ruff-0.16.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:258f29035a2dd021e7861e631b227a5b3f14e50c1184c9a6a122c5f4576154d7", size = 10534835, upload-time = "2026-08-27T16:33:52.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/5a/f0cf109bada9bba0e96c90c21c9f9251803f57225c32d293327a03c710d6/ruff-0.16.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9a4f0432966834019c74d1b7e5c51224305d7713f3d7faf3e7451f1a3be3cde", size = 11252550, upload-time = "2026-08-27T16:33:54.521Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
|
{ url = "https://files.pythonhosted.org/packages/63/4d/1d481aaea2046c6a7ed7c291f9004c669cce3c087b6b376ed5b08271e3fe/ruff-0.16.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5eb3a8c3d0ade9cea42b591fd530368e8798380e30e0a308b85a5cf718f09ea", size = 10777949, upload-time = "2026-08-27T16:33:56.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/34/ee245ca55f64443233034b3d02b03236b19242004281247c079390b7facd/ruff-0.16.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0f69e191a13a3c9816f63163c88790cb12cd157bbbb384e9c44745702ab105", size = 10311656, upload-time = "2026-08-27T16:33:59.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/c33a333e341c0a2b96c715b52d89a606f5a34cd4ac493cd9b8d0187186b8/ruff-0.16.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0eeab41fbea2c42f98dfb9822cdccda9d24ba38d49f6dc945b5c236d48f0ef29", size = 10532125, upload-time = "2026-08-27T16:34:01.166Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/e1/a64cef78b40192497bb98a27a8aa8f2c98ee9ee15bc97f7712d94ef32937/ruff-0.16.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0768e9df4300713fff30733c87575f68b6f1d8de41184e505b7fdd9c0c95eaf", size = 10097648, upload-time = "2026-08-27T16:34:03.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/4e/4cdc9ed3c3e109d2f71e62572a37457298d7bc7501ec3138babb7ed32bbd/ruff-0.16.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:95cc70cdc7aa80c338de356279d2adbeb2de0f520b9ecd8aba75b94e95e02f91", size = 9829344, upload-time = "2026-08-27T16:34:05.134Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/4a/31ed35ce31729955fc583ee0d176d6e784c1290cb0b0a75cb2134c1ab72a/ruff-0.16.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d185c8398ded1bfd91c0c2cb258346307571eccc473a8490af8c3977399c384a", size = 10277117, upload-time = "2026-08-27T16:34:07.425Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a0/60356d86687b4b666d593df213f4dc3041750d024cb7bf2cfa81cfd65c2e/ruff-0.16.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fb8e3a3c4c6a784150a7ced53b015f4b253fc2bf97a610886419ead64b4756ef", size = 10711653, upload-time = "2026-08-27T16:34:09.712Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/20/656d67f5b25ca9bda4e02b1de25867b2954e1d19e03648060f167ad0f4cc/ruff-0.16.5-py3-none-win32.whl", hash = "sha256:288b0a5f080492fe5635db849f9e2e84aa3cce7b7f0e955997d416c507c76a26", size = 10034250, upload-time = "2026-08-27T16:34:11.8Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/42/ee8e68a207b9127fcde6c3d7e197def432f346cb1af159e1fa14ca0d1cdc/ruff-0.16.5-py3-none-win_amd64.whl", hash = "sha256:ddc6385fb2137f616357ca03d6c74f4be987f80fed4008566b754f6032b8546f", size = 10516714, upload-time = "2026-08-27T16:34:13.963Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
|
{ url = "https://files.pythonhosted.org/packages/73/e3/7df5a396e445b9ba49ce9a9437439a4d80042c61c0ade199abf8d16de1ac/ruff-0.16.5-py3-none-win_arm64.whl", hash = "sha256:a64abe90968719b851bb7cedffaa8753fbdbdadab483089682db623f3edc587e", size = 10391564, upload-time = "2026-08-27T16:34:16.064Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -897,27 +897,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.55"
|
version = "0.0.75"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/48/f687c8d268e3581f2f104d1f2ac5944d5b5e841b3695c613b3f263e5bbf7/ty-0.0.55.tar.gz", hash = "sha256:88ca87073825a79a8327c550efcc86cec94344890244c5946f84c9e44a969f31", size = 6040230, upload-time = "2026-06-27T00:27:29.385Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/81/d0/d0c96f898d6974a4a3569ab3efdf9512c04ad99f9203effb55f72497fe97/ty-0.0.75.tar.gz", hash = "sha256:4c5eead33dfbf6e2ebb4f400f74b51ffc9bab702a6f23ddb648a1cbb740387e3", size = 6868326, upload-time = "2026-08-26T20:23:40.399Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/a3/1a90ba7e5a61c6d09adb92346ddba97668095fc257b577af433e5ac4f404/ty-0.0.55-py3-none-linux_armv6l.whl", hash = "sha256:31e83eef512d066542fe990fe1a3b814423abd1616376c54e48af7045b3e1749", size = 11677249, upload-time = "2026-06-27T00:26:52.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/6c/b12d03505f17581f0cfa3c12273fe34c1d67b36dfda1bc561a6bdc16512b/ty-0.0.75-py3-none-linux_armv6l.whl", hash = "sha256:e5409f50db2246fd4bd039d93d261e0cfa1daa554a4fb77256f91072c570349a", size = 12972606, upload-time = "2026-08-26T20:22:59.716Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/3a/669f9aa478c38243e213a2684db1502086026cfadc15bb1b29b7cbde030d/ty-0.0.55-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab4bca857950608fea73e269e2da369d43e6467131de85160d68e2fa466fa248", size = 11444180, upload-time = "2026-06-27T00:26:54.576Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/aa/30f11eecd9215a9f87e8fe8baaf48f3ce905f5d75b8e4aac70f0091f130c/ty-0.0.75-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5e7b8b3472fb9bb2eeab314984b265df08a7a9d518867a9e6020eebc06570be2", size = 12527158, upload-time = "2026-08-26T20:23:02.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/a4/6a4b2507a53ce6530c66c5b4fe0d58551eb1748ffa9e0696c32fdd55bbd4/ty-0.0.55-py3-none-macosx_11_0_arm64.whl", hash = "sha256:55032bfd31bf2c5355ee81bdc6407b144a1cc7ee41e5681dd1368e4cef2ba327", size = 10963134, upload-time = "2026-06-27T00:26:57.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/f2/11/7fd7001b0b5c6610bfbad7357e47d5fe6f82d4e84e94c53776a478f5e9f8/ty-0.0.75-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c6ccf34169821fe0d23e3360deeef981d217963412f1d087b9bdd32ec57f7a57", size = 12400533, upload-time = "2026-08-26T20:23:04.965Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/ae/a3b1a0f1cc83b7d258662cb98aa80a720c2e671d0e8fa0d17a4d5d057a7a/ty-0.0.55-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1e049f69ce65b3c269af67624607f435e1c32319786c1e453ef9611502f295", size = 11493517, upload-time = "2026-06-27T00:26:59.26Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/7f/1e284ea3d348d7be02f12d83bc22ed9ef193033f863f05b64db99027f141/ty-0.0.75-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842ebb41e9c6c334b40768704e20b1a69d5c6b08805b289d5e0e2565f49f2de1", size = 12420592, upload-time = "2026-08-26T20:23:07.427Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/9f/311ce39065a979ef40a9b847f685c8e02464e53adf1671e081eea90640ca/ty-0.0.55-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:631409975c681d5a280fc5a99b7b32e9e801f33be7567c6b42ec331362f59d7d", size = 11460590, upload-time = "2026-06-27T00:27:01.425Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/ab/d813271543370c47fd74b5118f2066ab32b0983e907b1821f3f9a6d0fa7f/ty-0.0.75-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7a5a723c5f1e0fab4ffbfe9bd95123a526ed48f206e5f25cb2161ca294007a", size = 12739219, upload-time = "2026-08-26T20:23:09.809Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/8f/3bf29aa77bd78aae48275153135a2052fa7d3ccdf1ecabeb99c8773abd66/ty-0.0.55-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e08cb0436e68b9351555ae8f2697138c9009b4d5b4ae4272232988b2a431a98f", size = 12098430, upload-time = "2026-06-27T00:27:03.596Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/5b/95b49cc5570fd92a7bf63732f649b31906158721e03c7fcb1b5be74ee3bf/ty-0.0.75-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54382f98e5da292fcd7104391afef5105c35bb2f312e29bea6f5fa419935255c", size = 13494046, upload-time = "2026-08-26T20:23:12.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6e/e88411a88240b94640bba06fb6d0d92b247fbeef47ee2bc71f39e58c2558/ty-0.0.55-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16c215ad9f823829409b94ee188cfaa4563f6e1384f6ce3fecb1db75f6c7cf7c", size = 12673086, upload-time = "2026-06-27T00:27:05.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/0d/502d2dd68173cf020e1ad2bdbab9544c86776de0b0e2ed15f8c2fe006e3d/ty-0.0.75-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac13b180dc2aade2cd243f56b01650e78bf091a2e522ad3bc947245d7837c613", size = 13938899, upload-time = "2026-08-26T20:23:14.764Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/7e/8f1762fb7f9245a68ba5ae338d73c59403ce57554e5d311b8bb55027b0ec/ty-0.0.55-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b510eb8f4032baf11b7aee2f1d53babc3b4ca03939b9cdcf6a9d15761d575188", size = 12242559, upload-time = "2026-06-27T00:27:07.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/5b/f3b12a25c07224456219fc2bd20db0ad7e40b304be0ff6aad728da0135f9/ty-0.0.75-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:752df7951a443219d7f1ff817e3723c85d428565ff449e08a7a93ba821661526", size = 13656711, upload-time = "2026-08-26T20:23:17.145Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/1f/143657daf2670d977dac83435f1fe03d4843efb798d8e1e75950e541aadd/ty-0.0.55-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc05e7959709c3b9b83aa627128a80446865e3c1a4882638dcff6d776dc34a", size = 12021409, upload-time = "2026-06-27T00:27:09.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/7b/f090ad306e2b15a07b332d647138c5264b89d9758855ecce8b8a10bcb153/ty-0.0.75-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd399feedf7cee816563c1baec45fc1c0b3c89f1ea42364920b688004b5b7da", size = 13093499, upload-time = "2026-08-26T20:23:19.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/30/69487c439dd1fad3a4a3d96f0a472193de297eaba6fc4b8ea687ce434ac2/ty-0.0.55-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:636e8e5078787b8c6916c94e1406719f10189a4ca6b37b813a5922ce5857a8c7", size = 12303807, upload-time = "2026-06-27T00:27:11.986Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/4b/f69b99aaaca0c7c65d5f114b186b26b21666f767b0c69eec99a2bdccc061/ty-0.0.75-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d7625f6f56c7dc1e873579fdc9e432a0e21e302afe847ab60704d2303442a92e", size = 13520580, upload-time = "2026-08-26T20:23:21.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/ca/cd88b6493dafc7db077f5e17c0438eb3af6e2d6d08f616dbb52a8ddfd567/ty-0.0.55-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ef7d6deaacb73fec603666b5471f1dc5a5699aa84e11a6d4d644dd07ca72121e", size = 11441263, upload-time = "2026-06-27T00:27:14.087Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/e7/692c5f905c0345a15d2255fc74066d660f030254ae8dcdaf33f5a5c2f279/ty-0.0.75-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:89e7d527e95a2534b70cae29e94c104b84082760ea05927d23bb87280969c104", size = 12524095, upload-time = "2026-08-26T20:23:24.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/fe/66b6915671653ab739f71e4f1b0528e69da64429b7ebf3840c625b6e43f2/ty-0.0.55-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9aeea0fe5875d3cf37faf0e44d0fdf9669335467749741b8fc0103916fb5cd32", size = 11484584, upload-time = "2026-06-27T00:27:16.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/9a/f42b12cf265ea95344bf554764c4791cfb273bdd628aadd7c209af7cadc3/ty-0.0.75-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0843f134440740706e01bee5f88f4cfc10e9b018bddb9e4ef4c12dc9fc0c9aef", size = 12756591, upload-time = "2026-08-26T20:23:26.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/4f/7a9c0bbac8b899e9f6c0ec110c6612f52e4db35f6bb17ddc0ef60384fa3e/ty-0.0.55-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b699c01310dbd2705a07c97c5f4aaeedef61bd9adeea2e7c46aed32401d3576", size = 11759309, upload-time = "2026-06-27T00:27:18.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/5e/9b180c133cb9cce48179a7d2bf9e1802d992aa8176a918e0e05205760b42/ty-0.0.75-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1bd0ec0e50ee1376875c88891efe6f549c3560fa5b2ddad79a425cd5a6218b9c", size = 12998754, upload-time = "2026-08-26T20:23:28.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/de/b6f8b1b69aa631b5716ef3f985c3b56de0e46c2499cc00d30c402b41f714/ty-0.0.55-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32cbeba543e46de2a983ec6d525d8b56514f7422bd1e1b57c44ccf7bfa72c38a", size = 12128755, upload-time = "2026-06-27T00:27:20.55Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/f6/3c6ef5dd550103e29905121c67fb96a374564f31a2f44c6faa1af98c2d61/ty-0.0.75-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f9eafd561f90110d5e29f589ec3e956c4686e2f6631348d99276436f5cbe4d1", size = 13316474, upload-time = "2026-08-26T20:23:30.857Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/90/a912531e51ee7e076b42972479290fa687c0f5e747b7e773f3033164acaa/ty-0.0.55-py3-none-win32.whl", hash = "sha256:52b968e24eb4f7a5c3bd251db1f99f60dd385890356d38fc619d84f1b423446a", size = 11117501, upload-time = "2026-06-27T00:27:22.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/52/12776337874c821076bd5368e352ccd9e67174790abe3b856f749cb3524b/ty-0.0.75-py3-none-win32.whl", hash = "sha256:05063a6fafe2154b794a7f964515d148e51acd186d72d4a3acd347ee9fa19336", size = 12316315, upload-time = "2026-08-26T20:23:33.528Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/7a/99d59843bf8908a7f9f4d13fda107dbad07b7faa28ecd7860eacf363fb1c/ty-0.0.55-py3-none-win_amd64.whl", hash = "sha256:bf39cbfdc0add44d94bd3fff1f53c351418d134b6a66b87efdb7876d7b7a2224", size = 12150106, upload-time = "2026-06-27T00:27:24.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/e6/bb51e16af5c7138c9f52f8f3d0a401a371c6798d092e3b74926f186a9814/ty-0.0.75-py3-none-win_amd64.whl", hash = "sha256:81cf1ba5f6b7536ad56747865214255d9bc8e80533a689dbb9ddeaad464b09f1", size = 12917267, upload-time = "2026-08-26T20:23:35.978Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/44/20987505cedf2a865b08482f0eabc181fd9599b062964057ec8a128a4296/ty-0.0.55-py3-none-win_arm64.whl", hash = "sha256:f7f3700a9a060e8f1af11e4fb63fafcaf272b041781f4ccdfda2b3b5c6c1e439", size = 11560157, upload-time = "2026-06-27T00:27:27.332Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/73/4542f829107468b5de4231af67f29927c093bfad11f3c1e5b2c08fb1206b/ty-0.0.75-py3-none-win_arm64.whl", hash = "sha256:541c9af5b7a0ad23d15ec315a7da81150833c359f48124ed3789ff25eacd6f42", size = 12711024, upload-time = "2026-08-26T20:23:38.159Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -67,24 +67,12 @@ with PostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|||||||
"v": 4,
|
"v": 4,
|
||||||
"ts": "2024-07-31T20:14:19.804150+00:00",
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
||||||
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
||||||
"channel_values": {
|
"channel_values": {"my_key": "meow", "node": "node"},
|
||||||
"my_key": "meow",
|
"channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node": 3},
|
||||||
"node": "node"
|
|
||||||
},
|
|
||||||
"channel_versions": {
|
|
||||||
"__start__": 2,
|
|
||||||
"my_key": 3,
|
|
||||||
"start:node": 3,
|
|
||||||
"node": 3
|
|
||||||
},
|
|
||||||
"versions_seen": {
|
"versions_seen": {
|
||||||
"__input__": {},
|
"__input__": {},
|
||||||
"__start__": {
|
"__start__": {"__start__": 1},
|
||||||
"__start__": 1
|
"node": {"start:node": 2},
|
||||||
},
|
|
||||||
"node": {
|
|
||||||
"start:node": 2
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,24 +96,12 @@ async with AsyncPostgresSaver.from_conn_string(DB_URI) as checkpointer:
|
|||||||
"v": 4,
|
"v": 4,
|
||||||
"ts": "2024-07-31T20:14:19.804150+00:00",
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
||||||
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
||||||
"channel_values": {
|
"channel_values": {"my_key": "meow", "node": "node"},
|
||||||
"my_key": "meow",
|
"channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node": 3},
|
||||||
"node": "node"
|
|
||||||
},
|
|
||||||
"channel_versions": {
|
|
||||||
"__start__": 2,
|
|
||||||
"my_key": 3,
|
|
||||||
"start:node": 3,
|
|
||||||
"node": 3
|
|
||||||
},
|
|
||||||
"versions_seen": {
|
"versions_seen": {
|
||||||
"__input__": {},
|
"__input__": {},
|
||||||
"__start__": {
|
"__start__": {"__start__": 1},
|
||||||
"__start__": 1
|
"node": {"start:node": 2},
|
||||||
},
|
|
||||||
"node": {
|
|
||||||
"start:node": 2
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ class PostgresSaver(BasePostgresSaver):
|
|||||||
>>> checkpoint_tuple = memory.get_tuple(config)
|
>>> checkpoint_tuple = memory.get_tuple(config)
|
||||||
>>> print(checkpoint_tuple)
|
>>> print(checkpoint_tuple)
|
||||||
CheckpointTuple(...)
|
CheckpointTuple(...)
|
||||||
""" # noqa
|
"""
|
||||||
thread_id = config["configurable"]["thread_id"]
|
thread_id = config["configurable"]["thread_id"]
|
||||||
checkpoint_id = get_checkpoint_id(config)
|
checkpoint_id = get_checkpoint_id(config)
|
||||||
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
||||||
@@ -478,9 +478,11 @@ class PostgresSaver(BasePostgresSaver):
|
|||||||
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
|
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
|
||||||
parent_of: dict[str, str | None] = {}
|
parent_of: dict[str, str | None] = {}
|
||||||
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
|
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
|
||||||
hs_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
|
hb_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
|
||||||
|
inline_by_i_by_cid: list[dict[str, Any]] = [{} for _ in channels]
|
||||||
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
|
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
|
||||||
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
|
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
|
||||||
|
seed_inline_by_ch: dict[str, Any] = {}
|
||||||
walk_cursor_by_ch: dict[str, str | None] = {}
|
walk_cursor_by_ch: dict[str, str | None] = {}
|
||||||
seeded: set[str] = set()
|
seeded: set[str] = set()
|
||||||
cursor: str | None = None
|
cursor: str | None = None
|
||||||
@@ -489,7 +491,8 @@ class PostgresSaver(BasePostgresSaver):
|
|||||||
while True:
|
while True:
|
||||||
stage1_params: list[Any] = []
|
stage1_params: list[Any] = []
|
||||||
for ch in channels:
|
for ch in channels:
|
||||||
stage1_params.extend([ch, ch])
|
# ver_i, blob channel, blob version, inline_i
|
||||||
|
stage1_params.extend([ch, ch, ch, ch])
|
||||||
stage1_params.extend(
|
stage1_params.extend(
|
||||||
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
|
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
|
||||||
)
|
)
|
||||||
@@ -502,16 +505,19 @@ class PostgresSaver(BasePostgresSaver):
|
|||||||
channels,
|
channels,
|
||||||
parent_of,
|
parent_of,
|
||||||
ver_by_i_by_cid,
|
ver_by_i_by_cid,
|
||||||
hs_by_i_by_cid,
|
hb_by_i_by_cid,
|
||||||
|
inline_by_i_by_cid,
|
||||||
)
|
)
|
||||||
self._try_advance_walks(
|
self._try_advance_walks(
|
||||||
checkpoint_id,
|
checkpoint_id,
|
||||||
channels,
|
channels,
|
||||||
parent_of,
|
parent_of,
|
||||||
ver_by_i_by_cid,
|
ver_by_i_by_cid,
|
||||||
hs_by_i_by_cid,
|
hb_by_i_by_cid,
|
||||||
|
inline_by_i_by_cid,
|
||||||
chain_by_ch,
|
chain_by_ch,
|
||||||
seed_ver_by_ch,
|
seed_ver_by_ch,
|
||||||
|
seed_inline_by_ch,
|
||||||
walk_cursor_by_ch,
|
walk_cursor_by_ch,
|
||||||
seeded,
|
seeded,
|
||||||
)
|
)
|
||||||
@@ -546,6 +552,7 @@ class PostgresSaver(BasePostgresSaver):
|
|||||||
channels=channels,
|
channels=channels,
|
||||||
chain_by_ch=chain_by_ch,
|
chain_by_ch=chain_by_ch,
|
||||||
seed_ver_by_ch=seed_ver_by_ch,
|
seed_ver_by_ch=seed_ver_by_ch,
|
||||||
|
seed_inline_by_ch=seed_inline_by_ch,
|
||||||
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
|
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -426,9 +426,11 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|||||||
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
|
stage1_sql = _build_delta_stage1_sql(channels, paged=True)
|
||||||
parent_of: dict[str, str | None] = {}
|
parent_of: dict[str, str | None] = {}
|
||||||
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
|
ver_by_i_by_cid: list[dict[str, str | None]] = [{} for _ in channels]
|
||||||
hs_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
|
hb_by_i_by_cid: list[dict[str, bool]] = [{} for _ in channels]
|
||||||
|
inline_by_i_by_cid: list[dict[str, Any]] = [{} for _ in channels]
|
||||||
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
|
chain_by_ch: dict[str, list[str]] = {ch: [] for ch in channels}
|
||||||
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
|
seed_ver_by_ch: dict[str, str | None] = {ch: None for ch in channels}
|
||||||
|
seed_inline_by_ch: dict[str, Any] = {}
|
||||||
walk_cursor_by_ch: dict[str, str | None] = {}
|
walk_cursor_by_ch: dict[str, str | None] = {}
|
||||||
seeded: set[str] = set()
|
seeded: set[str] = set()
|
||||||
cursor: str | None = None
|
cursor: str | None = None
|
||||||
@@ -437,7 +439,8 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|||||||
while True:
|
while True:
|
||||||
stage1_params: list[Any] = []
|
stage1_params: list[Any] = []
|
||||||
for ch in channels:
|
for ch in channels:
|
||||||
stage1_params.extend([ch, ch])
|
# ver_i, blob channel, blob version, inline_i
|
||||||
|
stage1_params.extend([ch, ch, ch, ch])
|
||||||
stage1_params.extend(
|
stage1_params.extend(
|
||||||
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
|
[thread_id, checkpoint_ns, cursor, cursor, _DELTA_PAGE_SIZE]
|
||||||
)
|
)
|
||||||
@@ -450,16 +453,19 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|||||||
channels,
|
channels,
|
||||||
parent_of,
|
parent_of,
|
||||||
ver_by_i_by_cid,
|
ver_by_i_by_cid,
|
||||||
hs_by_i_by_cid,
|
hb_by_i_by_cid,
|
||||||
|
inline_by_i_by_cid,
|
||||||
)
|
)
|
||||||
self._try_advance_walks(
|
self._try_advance_walks(
|
||||||
checkpoint_id,
|
checkpoint_id,
|
||||||
channels,
|
channels,
|
||||||
parent_of,
|
parent_of,
|
||||||
ver_by_i_by_cid,
|
ver_by_i_by_cid,
|
||||||
hs_by_i_by_cid,
|
hb_by_i_by_cid,
|
||||||
|
inline_by_i_by_cid,
|
||||||
chain_by_ch,
|
chain_by_ch,
|
||||||
seed_ver_by_ch,
|
seed_ver_by_ch,
|
||||||
|
seed_inline_by_ch,
|
||||||
walk_cursor_by_ch,
|
walk_cursor_by_ch,
|
||||||
seeded,
|
seeded,
|
||||||
)
|
)
|
||||||
@@ -490,6 +496,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|||||||
channels=channels,
|
channels=channels,
|
||||||
chain_by_ch=chain_by_ch,
|
chain_by_ch=chain_by_ch,
|
||||||
seed_ver_by_ch=seed_ver_by_ch,
|
seed_ver_by_ch=seed_ver_by_ch,
|
||||||
|
seed_inline_by_ch=seed_inline_by_ch,
|
||||||
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
|
stage2_rows=cast("list[_DeltaStage2Row]", stage2_rows),
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -573,7 +580,7 @@ class AsyncPostgresSaver(BasePostgresSaver):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
yield asyncio.run_coroutine_threadsafe(
|
yield asyncio.run_coroutine_threadsafe(
|
||||||
anext(aiter_), # type: ignore[arg-type] # noqa: F821
|
anext(aiter_), # type: ignore[arg-type]
|
||||||
self.loop,
|
self.loop,
|
||||||
).result()
|
).result()
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
|
|||||||
@@ -199,27 +199,68 @@ class _DeltaStage2Row(TypedDict, total=False):
|
|||||||
|
|
||||||
|
|
||||||
def _build_delta_stage1_sql(channels: Sequence[str], *, paged: bool) -> str:
|
def _build_delta_stage1_sql(channels: Sequence[str], *, paged: bool) -> str:
|
||||||
"""Build stage 1 SQL with 2K parallel JSONB key lookups.
|
"""Build stage 1 SQL with K parallel version lookups + seed probes.
|
||||||
|
|
||||||
For channels=["messages", "files"] (with `paged=True`) the result is::
|
For channels=["messages", "files"] (with `paged=True`) the result is::
|
||||||
|
|
||||||
SELECT checkpoint_id, parent_checkpoint_id,
|
SELECT checkpoint_id, parent_checkpoint_id,
|
||||||
checkpoint -> 'channel_versions' ->> %s AS ver_0,
|
checkpoint -> 'channel_versions' ->> %s AS ver_0,
|
||||||
(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_0,
|
EXISTS (SELECT 1 FROM checkpoint_blobs b0
|
||||||
|
WHERE b0.thread_id = checkpoints.thread_id
|
||||||
|
AND b0.checkpoint_ns = checkpoints.checkpoint_ns
|
||||||
|
AND b0.channel = %s
|
||||||
|
AND b0.version = checkpoint -> 'channel_versions' ->> %s
|
||||||
|
AND b0.type <> 'empty') AS hb_0,
|
||||||
|
checkpoint -> 'channel_values' -> %s AS inline_0,
|
||||||
checkpoint -> 'channel_versions' ->> %s AS ver_1,
|
checkpoint -> 'channel_versions' ->> %s AS ver_1,
|
||||||
(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_1
|
EXISTS (...) AS hb_1,
|
||||||
|
checkpoint -> 'channel_values' -> %s AS inline_1
|
||||||
FROM checkpoints
|
FROM checkpoints
|
||||||
WHERE thread_id = %s AND checkpoint_ns = %s
|
WHERE thread_id = %s AND checkpoint_ns = %s
|
||||||
AND (%s::text IS NULL OR checkpoint_id < %s)
|
AND (%s::text IS NULL OR checkpoint_id < %s)
|
||||||
ORDER BY checkpoint_id DESC
|
ORDER BY checkpoint_id DESC
|
||||||
LIMIT %s
|
LIMIT %s
|
||||||
|
|
||||||
Channel names are passed as `%s` parameters (safe from SQL injection).
|
A stored value for a channel lives in one of two places, because `put`
|
||||||
Only the column aliases `ver_i` / `hs_i` are interpolated into the
|
splits them:
|
||||||
SQL string (i is bounded by len(channels) and uses safe identifiers).
|
|
||||||
|
|
||||||
Caller must extend params with `[ch_0, ch_0, ch_1, ch_1, ...,
|
* **blob** — non-primitive values (and `_DeltaSnapshot`) are moved to
|
||||||
thread_id, ns, cursor, cursor, page_size]` when `paged=True`.
|
`checkpoint_blobs`. `hb_i` ("has blob") probes for one. The probe hits
|
||||||
|
that table's primary key `(thread_id, checkpoint_ns, channel, version)`
|
||||||
|
exactly, so it is an index lookup per row per channel.
|
||||||
|
* **inline** — `None`, `str`, `int`, `float` and `bool` stay in the
|
||||||
|
checkpoint's own `channel_values` and get no blob row at all. `inline_i`
|
||||||
|
returns that value.
|
||||||
|
|
||||||
|
Testing only for a key in `channel_values` (the previous approach) missed
|
||||||
|
blob-stored plain values, since `put` leaves an inline marker there for
|
||||||
|
`_DeltaSnapshot` but not for a plain value — which is what a thread
|
||||||
|
migrated from a pre-delta channel type leaves behind. Probing only the
|
||||||
|
blobs table would conversely miss inline primitives. Both are needed, and
|
||||||
|
the caller treats "either present" as the seed.
|
||||||
|
|
||||||
|
`hb_i` also disambiguates the two: for a `_DeltaSnapshot`, `inline_i` is the
|
||||||
|
literal `true` marker rather than the value, so a blob must win over an
|
||||||
|
inline reading whenever one exists. That ordering is what makes a genuine
|
||||||
|
inline `true` (a bool channel) distinguishable from the marker.
|
||||||
|
|
||||||
|
The `type <> 'empty'` predicate mirrors the check stage 2 already applies
|
||||||
|
when resolving the seed blob. `put` does not currently produce `empty` rows
|
||||||
|
on this path — `blob_versions` is filtered to keys present in
|
||||||
|
`channel_values`, so `_dump_blobs`' empty branch is unreachable from it —
|
||||||
|
but without the predicate the two stages could disagree: stage 1 would
|
||||||
|
terminate the walk on a row stage 2 then discards, yielding no seed *and* a
|
||||||
|
truncated write chain, which is the failure this function exists to avoid.
|
||||||
|
|
||||||
|
Channel names are passed as `%s` parameters (safe from SQL injection).
|
||||||
|
Only the column aliases `ver_i` / `hb_i` / `inline_i` and the subquery alias
|
||||||
|
`b{i}` are interpolated into the SQL string (i is bounded by len(channels)
|
||||||
|
and uses safe identifiers).
|
||||||
|
|
||||||
|
Caller must extend params with `[ch_0 x4, ch_1 x4, ..., thread_id, ns,
|
||||||
|
cursor, cursor, page_size]` when `paged=True` — four per channel: the
|
||||||
|
version lookup, the blob's channel, the version the blob must match, and the
|
||||||
|
inline lookup.
|
||||||
|
|
||||||
When `paged=False`, the WHERE has no cursor predicate and there's no
|
When `paged=False`, the WHERE has no cursor predicate and there's no
|
||||||
LIMIT/ORDER BY — kept as a non-public helper for tests/diagnostics.
|
LIMIT/ORDER BY — kept as a non-public helper for tests/diagnostics.
|
||||||
@@ -228,7 +269,13 @@ def _build_delta_stage1_sql(channels: Sequence[str], *, paged: bool) -> str:
|
|||||||
for i in range(len(channels)):
|
for i in range(len(channels)):
|
||||||
cols.append(
|
cols.append(
|
||||||
f"checkpoint -> 'channel_versions' ->> %s AS ver_{i}, "
|
f"checkpoint -> 'channel_versions' ->> %s AS ver_{i}, "
|
||||||
f"(checkpoint -> 'channel_values' -> %s) IS NOT NULL AS hs_{i}"
|
f"EXISTS (SELECT 1 FROM checkpoint_blobs b{i} "
|
||||||
|
f"WHERE b{i}.thread_id = checkpoints.thread_id "
|
||||||
|
f"AND b{i}.checkpoint_ns = checkpoints.checkpoint_ns "
|
||||||
|
f"AND b{i}.channel = %s "
|
||||||
|
f"AND b{i}.version = checkpoint -> 'channel_versions' ->> %s "
|
||||||
|
f"AND b{i}.type <> 'empty') AS hb_{i}, "
|
||||||
|
f"checkpoint -> 'channel_values' -> %s AS inline_{i}"
|
||||||
)
|
)
|
||||||
sql = (
|
sql = (
|
||||||
"SELECT checkpoint_id, parent_checkpoint_id, "
|
"SELECT checkpoint_id, parent_checkpoint_id, "
|
||||||
@@ -342,7 +389,8 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
channels: Sequence[str],
|
channels: Sequence[str],
|
||||||
parent_of: dict[str, str | None],
|
parent_of: dict[str, str | None],
|
||||||
ver_by_i_by_cid: list[dict[str, str | None]],
|
ver_by_i_by_cid: list[dict[str, str | None]],
|
||||||
hs_by_i_by_cid: list[dict[str, bool]],
|
hb_by_i_by_cid: list[dict[str, bool]],
|
||||||
|
inline_by_i_by_cid: list[dict[str, Any]],
|
||||||
) -> str | None:
|
) -> str | None:
|
||||||
"""Fold one stage-1 page into the running walk-state mappings.
|
"""Fold one stage-1 page into the running walk-state mappings.
|
||||||
|
|
||||||
@@ -356,7 +404,8 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
parent_of[cid] = cast("str | None", r["parent_checkpoint_id"])
|
parent_of[cid] = cast("str | None", r["parent_checkpoint_id"])
|
||||||
for i in range(len(channels)):
|
for i in range(len(channels)):
|
||||||
ver_by_i_by_cid[i][cid] = cast("str | None", r.get(f"ver_{i}"))
|
ver_by_i_by_cid[i][cid] = cast("str | None", r.get(f"ver_{i}"))
|
||||||
hs_by_i_by_cid[i][cid] = bool(r.get(f"hs_{i}"))
|
hb_by_i_by_cid[i][cid] = bool(r.get(f"hb_{i}"))
|
||||||
|
inline_by_i_by_cid[i][cid] = r.get(f"inline_{i}")
|
||||||
# Rows are DESC; the last one is the smallest cid in the page.
|
# Rows are DESC; the last one is the smallest cid in the page.
|
||||||
oldest = cid
|
oldest = cid
|
||||||
return oldest
|
return oldest
|
||||||
@@ -367,9 +416,11 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
channels: Sequence[str],
|
channels: Sequence[str],
|
||||||
parent_of: Mapping[str, str | None],
|
parent_of: Mapping[str, str | None],
|
||||||
ver_by_i_by_cid: Sequence[Mapping[str, str | None]],
|
ver_by_i_by_cid: Sequence[Mapping[str, str | None]],
|
||||||
hs_by_i_by_cid: Sequence[Mapping[str, bool]],
|
hb_by_i_by_cid: Sequence[Mapping[str, bool]],
|
||||||
|
inline_by_i_by_cid: Sequence[Mapping[str, Any]],
|
||||||
chain_by_ch: dict[str, list[str]],
|
chain_by_ch: dict[str, list[str]],
|
||||||
seed_ver_by_ch: dict[str, str | None],
|
seed_ver_by_ch: dict[str, str | None],
|
||||||
|
seed_inline_by_ch: dict[str, Any],
|
||||||
walk_cursor_by_ch: dict[str, str | None],
|
walk_cursor_by_ch: dict[str, str | None],
|
||||||
seeded: set[str],
|
seeded: set[str],
|
||||||
) -> None:
|
) -> None:
|
||||||
@@ -377,14 +428,15 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
|
|
||||||
Uses the partial `parent_of` map accumulated so far. A walk stops
|
Uses the partial `parent_of` map accumulated so far. A walk stops
|
||||||
either because:
|
either because:
|
||||||
(a) it found a snapshot for its channel (channel becomes seeded),
|
(a) it found a stored value for its channel — a blob or an inline
|
||||||
|
primitive (channel becomes seeded),
|
||||||
(b) it reached a real root (parent_of[cid] is None — fully
|
(b) it reached a real root (parent_of[cid] is None — fully
|
||||||
materialized at this point), or
|
materialized at this point), or
|
||||||
(c) the next ancestor cid isn't in `parent_of` yet (waiting for
|
(c) the next ancestor cid isn't in `parent_of` yet (waiting for
|
||||||
a later page; the cursor stays put).
|
a later page; the cursor stays put).
|
||||||
|
|
||||||
Mutates `chain_by_ch`, `seed_ver_by_ch`, `walk_cursor_by_ch`, and
|
Mutates `chain_by_ch`, `seed_ver_by_ch`, `seed_inline_by_ch`,
|
||||||
`seeded` in place.
|
`walk_cursor_by_ch`, and `seeded` in place.
|
||||||
"""
|
"""
|
||||||
for i, ch in enumerate(channels):
|
for i, ch in enumerate(channels):
|
||||||
if ch in seeded:
|
if ch in seeded:
|
||||||
@@ -394,15 +446,22 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
walk_cursor_by_ch[ch] = parent_of.get(target_id)
|
walk_cursor_by_ch[ch] = parent_of.get(target_id)
|
||||||
cur_cid = walk_cursor_by_ch[ch]
|
cur_cid = walk_cursor_by_ch[ch]
|
||||||
ch_chain = chain_by_ch[ch]
|
ch_chain = chain_by_ch[ch]
|
||||||
hs_i = hs_by_i_by_cid[i]
|
hb_i = hb_by_i_by_cid[i]
|
||||||
|
inline_i = inline_by_i_by_cid[i]
|
||||||
ver_i = ver_by_i_by_cid[i]
|
ver_i = ver_by_i_by_cid[i]
|
||||||
while cur_cid is not None:
|
while cur_cid is not None:
|
||||||
if cur_cid not in parent_of:
|
if cur_cid not in parent_of:
|
||||||
# Need more pages to continue this walk.
|
# Need more pages to continue this walk.
|
||||||
break
|
break
|
||||||
ch_chain.append(cur_cid)
|
ch_chain.append(cur_cid)
|
||||||
if hs_i.get(cur_cid, False):
|
has_blob = hb_i.get(cur_cid, False)
|
||||||
|
inline = inline_i.get(cur_cid)
|
||||||
|
if has_blob or inline is not None:
|
||||||
|
# A blob wins: for a `_DeltaSnapshot` the inline reading is
|
||||||
|
# the `true` marker, not the value.
|
||||||
seed_ver_by_ch[ch] = ver_i.get(cur_cid)
|
seed_ver_by_ch[ch] = ver_i.get(cur_cid)
|
||||||
|
if not has_blob:
|
||||||
|
seed_inline_by_ch[ch] = inline
|
||||||
seeded.add(ch)
|
seeded.add(ch)
|
||||||
cur_cid = None
|
cur_cid = None
|
||||||
break
|
break
|
||||||
@@ -415,16 +474,23 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
channels: Sequence[str],
|
channels: Sequence[str],
|
||||||
chain_by_ch: Mapping[str, list[str]],
|
chain_by_ch: Mapping[str, list[str]],
|
||||||
seed_ver_by_ch: Mapping[str, str | None],
|
seed_ver_by_ch: Mapping[str, str | None],
|
||||||
|
seed_inline_by_ch: Mapping[str, Any],
|
||||||
stage2_rows: Sequence[_DeltaStage2Row],
|
stage2_rows: Sequence[_DeltaStage2Row],
|
||||||
) -> dict[str, DeltaChannelHistory]:
|
) -> dict[str, DeltaChannelHistory]:
|
||||||
"""Demux stage 2 rows per channel; produce per-channel histories.
|
"""Demux stage 2 rows per channel; produce per-channel histories.
|
||||||
|
|
||||||
stage2_rows carry `channel` on every row. We build per-channel
|
stage2_rows carry `channel` on every row. We build per-channel
|
||||||
`writes_by_cid` and per-channel `seed_blob` dicts, then assemble
|
`writes_by_cid` and per-channel `seed_blob` dicts, then assemble
|
||||||
a `DeltaChannelHistory` per requested channel. The `seed` key is omitted
|
a `DeltaChannelHistory` per requested channel.
|
||||||
when the walk reached root with no snapshot found, or when the
|
|
||||||
seed blob is sentinel "empty" — in both cases the consumer treats
|
A seed comes from the blobs table when the walk found one there, and
|
||||||
absence as "start empty".
|
otherwise from `seed_inline_by_ch` — `put` keeps `None`, `str`, `int`,
|
||||||
|
`float` and `bool` values in the checkpoint's own `channel_values` with
|
||||||
|
no blob row, so those never appear in `stage2_rows`.
|
||||||
|
|
||||||
|
The `seed` key is omitted when the walk reached root without finding a
|
||||||
|
stored value, or when the seed blob is sentinel "empty" — in both cases
|
||||||
|
the consumer treats absence as "start empty".
|
||||||
"""
|
"""
|
||||||
# writes_by_ch_by_cid[channel][cid] = list of (type, blob, task_id, idx)
|
# writes_by_ch_by_cid[channel][cid] = list of (type, blob, task_id, idx)
|
||||||
writes_by_ch_by_cid: dict[str, dict[str, list[tuple[str, bytes, str, int]]]] = {
|
writes_by_ch_by_cid: dict[str, dict[str, list[tuple[str, bytes, str, int]]]] = {
|
||||||
@@ -473,6 +539,10 @@ class BasePostgresSaver(BaseCheckpointSaver[str]):
|
|||||||
blob = seed_blob_by_ver.get((ch, seed_version))
|
blob = seed_blob_by_ver.get((ch, seed_version))
|
||||||
if blob is not None and blob[0] != "empty":
|
if blob is not None and blob[0] != "empty":
|
||||||
entry["seed"] = self.serde.loads_typed(blob)
|
entry["seed"] = self.serde.loads_typed(blob)
|
||||||
|
elif ch in seed_inline_by_ch:
|
||||||
|
# Inline primitive: stored in the checkpoint, not the blobs
|
||||||
|
# table, so stage 2 never returned a row for it.
|
||||||
|
entry["seed"] = seed_inline_by_ch[ch]
|
||||||
result[ch] = entry
|
result[ch] = entry
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -334,7 +334,7 @@ class ShallowPostgresSaver(BasePostgresSaver):
|
|||||||
>>> checkpoint_tuple = memory.get_tuple(config)
|
>>> checkpoint_tuple = memory.get_tuple(config)
|
||||||
>>> print(checkpoint_tuple)
|
>>> print(checkpoint_tuple)
|
||||||
CheckpointTuple(...)
|
CheckpointTuple(...)
|
||||||
""" # noqa
|
"""
|
||||||
thread_id = config["configurable"]["thread_id"]
|
thread_id = config["configurable"]["thread_id"]
|
||||||
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
||||||
args = (thread_id, checkpoint_ns)
|
args = (thread_id, checkpoint_ns)
|
||||||
@@ -885,7 +885,7 @@ class AsyncShallowPostgresSaver(BasePostgresSaver):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
yield asyncio.run_coroutine_threadsafe(
|
yield asyncio.run_coroutine_threadsafe(
|
||||||
anext(aiter_), # type: ignore[arg-type] # noqa: F821
|
anext(aiter_), # type: ignore[arg-type]
|
||||||
self.loop,
|
self.loop,
|
||||||
).result()
|
).result()
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import logging
|
|||||||
import re
|
import re
|
||||||
import threading
|
import threading
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Callable, Iterable, Iterator, Sequence
|
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import (
|
from typing import (
|
||||||
@@ -354,7 +354,7 @@ class BasePostgresStore(Generic[C]):
|
|||||||
(
|
(
|
||||||
_namespace_to_text(op.namespace),
|
_namespace_to_text(op.namespace),
|
||||||
op.key,
|
op.key,
|
||||||
Jsonb(cast(dict, op.value)),
|
Jsonb(dict(cast(Mapping[str, Any], op.value))),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
if op.ttl is not None:
|
if op.ttl is not None:
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "langgraph-checkpoint-postgres"
|
name = "langgraph-checkpoint-postgres"
|
||||||
version = "3.1.1"
|
version = "3.1.2"
|
||||||
description = "Library with a Postgres implementation of LangGraph checkpoint saver."
|
description = "Library with a Postgres implementation of LangGraph checkpoint saver."
|
||||||
authors = []
|
authors = []
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@@ -32,6 +32,7 @@ test = [
|
|||||||
"pytest-mock",
|
"pytest-mock",
|
||||||
"psycopg[binary]",
|
"psycopg[binary]",
|
||||||
"langgraph-checkpoint",
|
"langgraph-checkpoint",
|
||||||
|
"langgraph-checkpoint-conformance",
|
||||||
"pytest-watcher",
|
"pytest-watcher",
|
||||||
]
|
]
|
||||||
lint = [
|
lint = [
|
||||||
@@ -49,6 +50,7 @@ default-groups = ['dev']
|
|||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
langgraph-checkpoint = { path = "../checkpoint", editable = true }
|
langgraph-checkpoint = { path = "../checkpoint", editable = true }
|
||||||
|
langgraph-checkpoint-conformance = { path = "../checkpoint-conformance", editable = true }
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
include = ["langgraph"]
|
include = ["langgraph"]
|
||||||
@@ -64,6 +66,8 @@ lint.select = [
|
|||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
|
"PLC0415", # import-outside-top-level
|
||||||
|
"RUF100", # unused noqa directive
|
||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
]
|
]
|
||||||
lint.ignore = ["E501", "B008"]
|
lint.ignore = ["E501", "B008"]
|
||||||
|
|||||||
@@ -380,13 +380,15 @@ async def test_delta_channel_chain_reconstruction(saver_name: str) -> None:
|
|||||||
"langgraph.channels.delta", reason="langgraph core not installed"
|
"langgraph.channels.delta", reason="langgraph core not installed"
|
||||||
)
|
)
|
||||||
|
|
||||||
from typing import Annotated
|
# Deferred on purpose: langgraph core is not a test dependency of this
|
||||||
|
# package, so these must stay behind the importorskip above.
|
||||||
|
from typing import Annotated # noqa: PLC0415
|
||||||
|
|
||||||
from langchain_core.messages import AIMessage, HumanMessage
|
from langchain_core.messages import AIMessage, HumanMessage # noqa: PLC0415
|
||||||
from langgraph.channels.delta import DeltaChannel
|
from langgraph.channels.delta import DeltaChannel # noqa: PLC0415
|
||||||
from langgraph.graph import START, StateGraph
|
from langgraph.graph import START, StateGraph # noqa: PLC0415
|
||||||
from langgraph.graph.message import _messages_delta_reducer
|
from langgraph.graph.message import _messages_delta_reducer # noqa: PLC0415
|
||||||
from typing_extensions import TypedDict
|
from typing_extensions import TypedDict # noqa: PLC0415
|
||||||
|
|
||||||
class State(TypedDict):
|
class State(TypedDict):
|
||||||
messages: Annotated[list, DeltaChannel(_messages_delta_reducer)]
|
messages: Annotated[list, DeltaChannel(_messages_delta_reducer)]
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
"""Run delta-channel conformance capabilities against AsyncPostgresSaver."""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from langgraph.checkpoint.conformance import validate
|
||||||
|
from langgraph.checkpoint.conformance.initializer import checkpointer_test
|
||||||
|
|
||||||
|
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
||||||
|
from tests.conftest import DEFAULT_URI
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delta_channel_conformance():
|
||||||
|
@checkpointer_test(name="AsyncPostgresSaver")
|
||||||
|
async def postgres_saver():
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
yield saver
|
||||||
|
|
||||||
|
report = await validate(
|
||||||
|
postgres_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}")
|
||||||
@@ -0,0 +1,204 @@
|
|||||||
|
"""Seed detection for `DeltaChannel` histories on Postgres.
|
||||||
|
|
||||||
|
`put` splits stored values in two: primitives stay inline in the checkpoint's
|
||||||
|
`channel_values`, everything else moves to `checkpoint_blobs`. Only
|
||||||
|
`_DeltaSnapshot` leaves an inline marker behind when it moves, so the stage-1
|
||||||
|
walk has to check both places — a blob probe alone misses inline primitives, and
|
||||||
|
an inline-key check alone missed blob-stored plain values, which is what a thread
|
||||||
|
migrated from a pre-delta channel type leaves behind. See #8534.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from typing import Any
|
||||||
|
from uuid import uuid4
|
||||||
|
|
||||||
|
import pytest
|
||||||
|
from langgraph.checkpoint.base import Checkpoint, empty_checkpoint
|
||||||
|
from langgraph.checkpoint.base.id import uuid6
|
||||||
|
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
||||||
|
|
||||||
|
from langgraph.checkpoint.postgres.aio import AsyncPostgresSaver
|
||||||
|
from tests.conftest import DEFAULT_URI
|
||||||
|
|
||||||
|
CHANNEL = "items"
|
||||||
|
|
||||||
|
|
||||||
|
async def _build_chain(saver: AsyncPostgresSaver, seed_value: Any) -> tuple[str, dict]:
|
||||||
|
"""Store `seed_value` at step 1, then two steps that store nothing.
|
||||||
|
|
||||||
|
Every step carries a write so the walk has something to collect.
|
||||||
|
Returns `(thread_id, head_config)`.
|
||||||
|
"""
|
||||||
|
thread_id = str(uuid4())
|
||||||
|
parent: dict | None = None
|
||||||
|
for step in range(4):
|
||||||
|
config: dict = {"configurable": {"thread_id": thread_id, "checkpoint_ns": ""}}
|
||||||
|
if parent is not None:
|
||||||
|
config["configurable"]["checkpoint_id"] = parent["configurable"][
|
||||||
|
"checkpoint_id"
|
||||||
|
]
|
||||||
|
cp: Checkpoint = empty_checkpoint()
|
||||||
|
cp["id"] = str(uuid6(clock_seq=step))
|
||||||
|
new_versions: dict[str, Any] = {}
|
||||||
|
if step == 1:
|
||||||
|
cp["channel_values"][CHANNEL] = seed_value
|
||||||
|
cp["channel_versions"][CHANNEL] = "v1"
|
||||||
|
new_versions[CHANNEL] = "v1"
|
||||||
|
else:
|
||||||
|
cp["channel_versions"][CHANNEL] = f"v{step}"
|
||||||
|
parent = await saver.aput(
|
||||||
|
config, cp, {"source": "loop", "step": step, "parents": {}}, new_versions
|
||||||
|
)
|
||||||
|
await saver.aput_writes(parent, [(CHANNEL, f"w{step}")], str(uuid4()))
|
||||||
|
assert parent is not None
|
||||||
|
return thread_id, parent
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_plain_value_seed_is_found() -> None:
|
||||||
|
"""A pre-delta plain value must be located as the seed.
|
||||||
|
|
||||||
|
Before #8534 the walk ran to the root and returned no seed, which happens
|
||||||
|
to reconstruct correctly for additive reducers while costing an
|
||||||
|
O(thread length) replay on every read.
|
||||||
|
"""
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
_, head = await _build_chain(saver, [10, 20])
|
||||||
|
|
||||||
|
result = await saver.aget_delta_channel_history(config=head, channels=[CHANNEL])
|
||||||
|
entry = result[CHANNEL]
|
||||||
|
|
||||||
|
assert entry.get("seed") == [10, 20], (
|
||||||
|
f"expected the plain value as seed, got {entry.get('seed', '<missing>')}"
|
||||||
|
)
|
||||||
|
# Only the writes between the seed and the head's parent replay: step 1
|
||||||
|
# (the seed's own) and step 2. Step 0 is older than the seed, step 3 is
|
||||||
|
# pending at the head.
|
||||||
|
assert [w[2] for w in entry["writes"]] == ["w1", "w2"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_delta_snapshot_seed_is_found() -> None:
|
||||||
|
"""The `_DeltaSnapshot` path keeps working, so both seed kinds agree."""
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
_, head = await _build_chain(saver, _DeltaSnapshot([10, 20]))
|
||||||
|
|
||||||
|
result = await saver.aget_delta_channel_history(config=head, channels=[CHANNEL])
|
||||||
|
entry = result[CHANNEL]
|
||||||
|
|
||||||
|
seed = entry.get("seed")
|
||||||
|
assert isinstance(seed, _DeltaSnapshot), f"expected a snapshot, got {seed!r}"
|
||||||
|
assert seed.value == [10, 20]
|
||||||
|
assert [w[2] for w in entry["writes"]] == ["w1", "w2"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_version_bump_without_a_value_does_not_hide_an_older_seed() -> None:
|
||||||
|
"""A delta-era step bumps `channel_versions` without storing a value, so no
|
||||||
|
blob exists for that version. The probe must report no seed there and keep
|
||||||
|
walking rather than stopping at a version it cannot resolve.
|
||||||
|
|
||||||
|
Step 0 holds the real value; step 1 bumps the version with nothing stored.
|
||||||
|
Walking back from the head has to pass step 1 to reach step 0.
|
||||||
|
"""
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
thread_id = str(uuid4())
|
||||||
|
parent: dict | None = None
|
||||||
|
for step in range(4):
|
||||||
|
config: dict = {
|
||||||
|
"configurable": {"thread_id": thread_id, "checkpoint_ns": ""}
|
||||||
|
}
|
||||||
|
if parent is not None:
|
||||||
|
config["configurable"]["checkpoint_id"] = parent["configurable"][
|
||||||
|
"checkpoint_id"
|
||||||
|
]
|
||||||
|
cp: Checkpoint = empty_checkpoint()
|
||||||
|
cp["id"] = str(uuid6(clock_seq=step))
|
||||||
|
new_versions: dict[str, Any] = {}
|
||||||
|
if step == 0:
|
||||||
|
cp["channel_values"][CHANNEL] = [10, 20]
|
||||||
|
cp["channel_versions"][CHANNEL] = "v0"
|
||||||
|
new_versions[CHANNEL] = "v0"
|
||||||
|
elif step == 1:
|
||||||
|
# Version bumped, value absent -> no blob row written.
|
||||||
|
cp["channel_versions"][CHANNEL] = "v1"
|
||||||
|
new_versions[CHANNEL] = "v1"
|
||||||
|
else:
|
||||||
|
cp["channel_versions"][CHANNEL] = "v1"
|
||||||
|
parent = await saver.aput(
|
||||||
|
config,
|
||||||
|
cp,
|
||||||
|
{"source": "loop", "step": step, "parents": {}},
|
||||||
|
new_versions,
|
||||||
|
)
|
||||||
|
await saver.aput_writes(parent, [(CHANNEL, f"w{step}")], str(uuid4()))
|
||||||
|
assert parent is not None
|
||||||
|
|
||||||
|
result = await saver.aget_delta_channel_history(
|
||||||
|
config=parent, channels=[CHANNEL]
|
||||||
|
)
|
||||||
|
entry = result[CHANNEL]
|
||||||
|
|
||||||
|
assert entry.get("seed") == [10, 20], (
|
||||||
|
"the walk stopped at the empty blob instead of reaching the real "
|
||||||
|
f"value at step 0; got {entry.get('seed', '<missing>')}"
|
||||||
|
)
|
||||||
|
assert [w[2] for w in entry["writes"]] == ["w0", "w1", "w2"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_inline_primitive_seed_is_found() -> None:
|
||||||
|
"""`put` keeps `None`, `str`, `int`, `float` and `bool` in the checkpoint's
|
||||||
|
own `channel_values` with no blob row, so a blob probe alone cannot see
|
||||||
|
them. Stage 1 reads the inline value too and uses it when there is no blob.
|
||||||
|
"""
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
for seed_value in (42, "x", 3.5, None):
|
||||||
|
_, head = await _build_chain(saver, seed_value)
|
||||||
|
entry = (
|
||||||
|
await saver.aget_delta_channel_history(config=head, channels=[CHANNEL])
|
||||||
|
)[CHANNEL]
|
||||||
|
if seed_value is None:
|
||||||
|
# A JSON null is indistinguishable from "no value stored", so
|
||||||
|
# the walk keeps going; replay from empty is the correct result.
|
||||||
|
assert "seed" not in entry
|
||||||
|
else:
|
||||||
|
assert entry.get("seed") == seed_value, (
|
||||||
|
f"inline {type(seed_value).__name__} seed not found: "
|
||||||
|
f"{entry.get('seed', '<missing>')!r}"
|
||||||
|
)
|
||||||
|
assert [w[2] for w in entry["writes"]] == ["w1", "w2"]
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.asyncio
|
||||||
|
async def test_inline_true_is_not_read_as_a_snapshot_marker() -> None:
|
||||||
|
"""`put` inlines a literal `true` in `channel_values` as the marker for a
|
||||||
|
`_DeltaSnapshot`, which is also what a genuine `bool` channel holding
|
||||||
|
`True` looks like. A blob exists only in the snapshot case, so preferring
|
||||||
|
the blob keeps the two apart.
|
||||||
|
"""
|
||||||
|
async with AsyncPostgresSaver.from_conn_string(DEFAULT_URI) as saver:
|
||||||
|
await saver.setup()
|
||||||
|
|
||||||
|
_, head = await _build_chain(saver, True)
|
||||||
|
entry = (
|
||||||
|
await saver.aget_delta_channel_history(config=head, channels=[CHANNEL])
|
||||||
|
)[CHANNEL]
|
||||||
|
assert entry.get("seed") is True, (
|
||||||
|
f"a real inline True must survive, got {entry.get('seed', '<missing>')!r}"
|
||||||
|
)
|
||||||
|
|
||||||
|
_, snap_head = await _build_chain(saver, _DeltaSnapshot(True))
|
||||||
|
snap_entry = (
|
||||||
|
await saver.aget_delta_channel_history(config=snap_head, channels=[CHANNEL])
|
||||||
|
)[CHANNEL]
|
||||||
|
seed = snap_entry.get("seed")
|
||||||
|
assert isinstance(seed, _DeltaSnapshot), (
|
||||||
|
f"the marker must resolve to the blob, not inline true; got {seed!r}"
|
||||||
|
)
|
||||||
|
assert seed.value is True
|
||||||
Generated
+147
-125
@@ -17,16 +17,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.14.1"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/3b/72/5562aabb8dd7181e8e860622a38bea08d17842b99ecd4c91f84ac95251b0/anyio-4.14.1.tar.gz", hash = "sha256:8d648a3544c1a700e3ff78615cd679e4c5c3f149904287e73687b2596963629e", size = 254831, upload-time = "2026-06-24T20:56:06.017Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/7b/90df4a0a816d98d6ea26f559d87836d494a2cf1fcf063be67df50a7bcc30/anyio-4.14.1-py3-none-any.whl", hash = "sha256:4e5533c5b8ff0a24f5d7a176cbe6877129cd183893f66b537f8f227d10527d72", size = 124875, upload-time = "2026-06-24T20:56:04.413Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -138,11 +138,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespell"
|
name = "codespell"
|
||||||
version = "2.4.2"
|
version = "2.4.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/80/19/45e941380f69c042b43423513d201e6592346f992394347f5e7174c31407/codespell-2.4.3.tar.gz", hash = "sha256:cbe085e331227b37bb86ef8bddd08dc768c704ee9a07ca869852c093fa2793e2", size = 352773, upload-time = "2026-07-15T11:51:54.159Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
|
{ url = "https://files.pythonhosted.org/packages/8b/bf/bdb951d34eb169140b546f44be9ec4525d1acefb9eb5572071f5492b19fc/codespell-2.4.3-py3-none-any.whl", hash = "sha256:af2505b335e8573dbd2d384d1c4ef498f4006f4ba2d6fceca01e55b91f52628a", size = 340736, upload-time = "2026-07-15T11:51:52.925Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -159,7 +159,7 @@ name = "exceptiongroup"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ 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" }
|
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 = [
|
wheels = [
|
||||||
@@ -244,7 +244,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.4.8"
|
version = "1.5.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
@@ -257,9 +257,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/12/e3/bea6d0080acf183332f24dcd74c208aee5857cf8f783c3fb0bd86027d8fb/langchain_core-1.4.8.tar.gz", hash = "sha256:5bf1f8411077c904182ad8f975943d36adcbf579c4e017b3a118b719229ebf9a", size = 957974, upload-time = "2026-06-18T19:39:23.636Z" }
|
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" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl", hash = "sha256:d84c28b05e3ba8d4271d0827aad5b592ccdaaf986e76768c23503f0a2045e8aa", size = 557416, upload-time = "2026-06-18T19:39:21.902Z" },
|
{ 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" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -276,7 +276,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.1.1"
|
version = "4.2.0"
|
||||||
source = { editable = "../checkpoint" }
|
source = { editable = "../checkpoint" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -322,9 +322,36 @@ test = [
|
|||||||
{ name = "redis" },
|
{ name = "redis" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "langgraph-checkpoint-conformance"
|
||||||
|
version = "0.0.2"
|
||||||
|
source = { editable = "../checkpoint-conformance" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "langgraph-checkpoint" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [{ name = "langgraph-checkpoint", editable = "../checkpoint" }]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "pytest-asyncio" },
|
||||||
|
{ name = "ruff" },
|
||||||
|
{ name = "ty" },
|
||||||
|
]
|
||||||
|
lint = [
|
||||||
|
{ name = "ruff" },
|
||||||
|
{ name = "ty" },
|
||||||
|
]
|
||||||
|
test = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "pytest-asyncio" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint-postgres"
|
name = "langgraph-checkpoint-postgres"
|
||||||
version = "3.1.1"
|
version = "3.1.2"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
@@ -338,6 +365,7 @@ dev = [
|
|||||||
{ name = "anyio" },
|
{ name = "anyio" },
|
||||||
{ name = "codespell" },
|
{ name = "codespell" },
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance" },
|
||||||
{ name = "psycopg", extra = ["binary"] },
|
{ name = "psycopg", extra = ["binary"] },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
@@ -354,6 +382,7 @@ lint = [
|
|||||||
test = [
|
test = [
|
||||||
{ name = "anyio" },
|
{ name = "anyio" },
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance" },
|
||||||
{ name = "psycopg", extra = ["binary"] },
|
{ name = "psycopg", extra = ["binary"] },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
@@ -374,6 +403,7 @@ dev = [
|
|||||||
{ name = "anyio" },
|
{ name = "anyio" },
|
||||||
{ name = "codespell" },
|
{ name = "codespell" },
|
||||||
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance", editable = "../checkpoint-conformance" },
|
||||||
{ name = "psycopg", extras = ["binary"] },
|
{ name = "psycopg", extras = ["binary"] },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
@@ -390,6 +420,7 @@ lint = [
|
|||||||
test = [
|
test = [
|
||||||
{ name = "anyio" },
|
{ name = "anyio" },
|
||||||
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance", editable = "../checkpoint-conformance" },
|
||||||
{ name = "psycopg", extras = ["binary"] },
|
{ name = "psycopg", extras = ["binary"] },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
@@ -420,83 +451,74 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "orjson"
|
name = "orjson"
|
||||||
version = "3.11.9"
|
version = "3.12.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/7e/0c/964746fcafbd16f8ff53219ad9f6b412b34f345c75f384ad434ceaadb538/orjson-3.11.9.tar.gz", hash = "sha256:4fef17e1f8722c11587a6ef18e35902450221da0028e65dbaaa543619e68e48f", size = 5599163, upload-time = "2026-05-06T15:11:08.309Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/0f/f3/742fb1f62b825f2c010697eaf4e828004bc2a81e7e806666989c132c7c42/orjson-3.12.0.tar.gz", hash = "sha256:d14203fb1aae2ad9b3d52f8a0e82aeb10197ef1c9bc61da7f358bd70b00123d5", size = 4142915, upload-time = "2026-08-14T16:13:30.607Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/5d/b95ca542a001135cc250a49370f282f578c8f4e46cc8617d73775297eea8/orjson-3.11.9-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:135869ef917b8704ea0a94e01620e0c05021c15c52036e4663baffe75e72f8ce", size = 228986, upload-time = "2026-05-06T15:09:14.765Z" },
|
{ url = "https://files.pythonhosted.org/packages/cf/35/819eeb4fa8ee676d38fdbb8213a76fd496f7dbbfdfafa89d34e02b22dfac/orjson-3.12.0-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:747843254519dd43b93eee3153a19e5a509334320c4d2f823ec879232db5c796", size = 224133, upload-time = "2026-08-14T16:12:00.607Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/80/01/be33fbff646e22f93398429ea645f20d2097aea1a6cdc1e6628e70125f83/orjson-3.11.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115ab5f5f4a0f203cc2a5f0fb09aee503a3f771aa08392949ab5ca230c4fbdbd", size = 132558, upload-time = "2026-05-06T15:09:17.431Z" },
|
{ url = "https://files.pythonhosted.org/packages/58/ab/d9221d4a2b085b073fcddc91728d490f20b9cf010c62c2f42371ab997695/orjson-3.12.0-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:7c2ad193c8004254f34b499f3bd2c80f043d10754aff2b38f93da574f4883f98", size = 113669, upload-time = "2026-08-14T16:12:02.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4e/61/73d49333bba660a075daccca10970dc6409ce1cf42ae4046646a19468aad/orjson-3.11.9-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4da3c38a2083ca4aaf9c2a36776cce3e9328e6647b10d118948f3cfb4913ffe4", size = 128213, upload-time = "2026-05-06T15:09:18.719Z" },
|
{ url = "https://files.pythonhosted.org/packages/15/12/644cbbcabb26df61d9ef0c66e6f2bf8b687cc7b66137597f2858951f1952/orjson-3.12.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:bc7a872f03522d90e0429e6c0c5cd23084f767bedcb4c58048eec19294613344", size = 130410, upload-time = "2026-08-14T16:12:03.503Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/7d/30e844b3dac3f74aed66b1f984daf9db3c98c0328c03d965a9e8dc06449e/orjson-3.11.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:53b50b0e14084b8f7e29c5ce84c5af0f1160169b30d8a6914231d97d2fe297d4", size = 135430, upload-time = "2026-05-06T15:09:20.257Z" },
|
{ url = "https://files.pythonhosted.org/packages/14/6d/e3a8c34d687895aecd8b267a01c46106eb98d8424a83bfa7bacb723854f6/orjson-3.12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18a87929f31d94a77f7dc93cf527e91f39ce7fe7813d588a4de2507efd32a387", size = 131101, upload-time = "2026-08-14T16:12:04.918Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/64/bd815f5c610b3facc204f26ba94e87a9eb49b0d83de3d5fc1eee2402d91b/orjson-3.11.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:231742b4a11dad8d5380a435962c57e91b7c37b79be858f4ef1c0df1a259897e", size = 146178, upload-time = "2026-05-06T15:09:21.616Z" },
|
{ url = "https://files.pythonhosted.org/packages/75/20/930824c07685c22af23f26818ed3853b0270488a412b6ab757904b7f787b/orjson-3.12.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e9683ee9ea0659da64f36574ef675b8a86330c34c19ea75db1fb93c3ff99e0ef", size = 131479, upload-time = "2026-08-14T16:12:06.11Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c7/35/e744fd36c79b339d27beb06068b5a08a8882ef5418804d0ce545a31f718d/orjson-3.11.9-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:34fd2317602587321faab75ab76c623a0117e80841a6413654f04e47f339a8fb", size = 133068, upload-time = "2026-05-06T15:09:23.228Z" },
|
{ url = "https://files.pythonhosted.org/packages/4c/a6/22e863bbbe8917aa292e33e0db597000f9a07eb5e6f52efed623fa16bae1/orjson-3.12.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:103b5db66aa53c1f9e88c2524be4f383e831ba7dfd5f9f5af6336a177c622f11", size = 135865, upload-time = "2026-08-14T16:12:07.392Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2a/56/d54152b67b63a0b3e556cfc549d6ce84f74d7f425ddeadc6c8a74d913da7/orjson-3.11.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:71f3db16e69b667b132e0f305a833d5497da302d801508cbb051ed9a9819da47", size = 134217, upload-time = "2026-05-06T15:09:24.847Z" },
|
{ url = "https://files.pythonhosted.org/packages/50/a0/ceb5008914a65e9a19a46a09d94bc67a74d120209fdfa772750023ceb377/orjson-3.12.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bd57d79aefa3f84eec851d6de7a366795b9345cfaf17f82b4820430a7a5fa241", size = 127843, upload-time = "2026-08-14T16:12:08.607Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/ee/66154baf69f71c7164a268a5e888908aec5a0819d13c81d5e2755a257758/orjson-3.11.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0b34789fa0da61cf7bef0546b09c738fb195331e017e477096d129e9105ab03d", size = 141917, upload-time = "2026-05-06T15:09:26.647Z" },
|
{ url = "https://files.pythonhosted.org/packages/12/3d/61c6b3b84c250cb09cb7229701ff77e4d763773ad7f577d0b6abf2892664/orjson-3.12.0-cp310-cp310-win32.whl", hash = "sha256:3dbce9b6b3074b31a5d5dd322a9c4e5b16f206091ece4194c2e36952847a105e", size = 128293, upload-time = "2026-08-14T16:12:09.819Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/d3/c5824260ca8b9d7ba82648d042a3f8f4815d18c15bb98a1f30edd1bb2d83/orjson-3.11.9-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:87e4d4ab280b0c87424d47695bec2182caf8cfc17879ea78dab76680194abc13", size = 415356, upload-time = "2026-05-06T15:09:28.252Z" },
|
{ url = "https://files.pythonhosted.org/packages/ce/0e/ea0f4a563253b6363195a4f704123c6bfbf156641bd3be5a75de81c5e917/orjson-3.12.0-cp310-cp310-win_amd64.whl", hash = "sha256:3bb17a06f9bd15237b3216c044209fe92597379124018cfc196fbb846cde64df", size = 122216, upload-time = "2026-08-14T16:12:11.261Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/cb/509c2e816fe4df641d93dc92f6a89adc8df3ada8ebdee2bd44aba3264c3c/orjson-3.11.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:ace6c58523302d3b97b6ac5c38a5298a54b473762b6be82726b4265c41029f92", size = 148112, upload-time = "2026-05-06T15:09:29.783Z" },
|
{ url = "https://files.pythonhosted.org/packages/75/1a/a7075a8e8b0d3f5097d17ac3099017104b6b7b42012041147995d5b2da05/orjson-3.12.0-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a94f0f0c6fcbb2b5bd9734c57a489c7584a732bbdf04a39e8c83b861e9d03e92", size = 223409, upload-time = "2026-08-14T16:12:12.654Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/db/b5/3ceae56d2e4962979eedb023ba6a46a4bb65f333960379be0ca470686220/orjson-3.11.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:97d0d932803c1b164fde11cb542a9efcb1e0f63b184537cca65887147906ff48", size = 137112, upload-time = "2026-05-06T15:09:31.432Z" },
|
{ url = "https://files.pythonhosted.org/packages/05/34/c2eb3b2900e5597db7841a4c6416ac2d90081bd956b02d4dd1833fa2b96b/orjson-3.12.0-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:a696529ec96a90d9a5f9570207efe403c8b08f8e4aa2783ee3403511e2fdfa10", size = 124015, upload-time = "2026-08-14T16:12:14.025Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/7a/81fa3f2c7bef79b04cf2ab7838e5ac74b1f12511ceab979759b0275d6bb4/orjson-3.11.9-cp310-cp310-win32.whl", hash = "sha256:b3afcf569c15577a9fe64627292daa3e6b3a70f4fb77a5df246a87ec21681b94", size = 131706, upload-time = "2026-05-06T15:09:32.707Z" },
|
{ url = "https://files.pythonhosted.org/packages/1c/df/b49081766a75b6a37b3d33bdc0a39e492abab8441dd25e3e1998e7b83fcb/orjson-3.12.0-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:e4ac5059baab4b3acbd99485de019ff8cda0fdf34b61fa74f7197a53db78bfe8", size = 113471, upload-time = "2026-08-14T16:12:15.81Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ae/d8/b64600f9083c7f151ad39717a5877fccbeb0ef6d7efcb55f971ce00b6bee/orjson-3.11.9-cp310-cp310-win_amd64.whl", hash = "sha256:8697ab6a080a5c46edaad50e2bc5bd8c7ca5c66442d24104fa44ec74910a8244", size = 127282, upload-time = "2026-05-06T15:09:33.955Z" },
|
{ url = "https://files.pythonhosted.org/packages/48/d4/58ea28eeef95c2a27358ed927380a621162cf20bd740bbccf9c3f09a200a/orjson-3.12.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:8e29957429c35bbb5a185a119c523aa2428b7bbf1a293724c7b9375ed8f892a3", size = 129998, upload-time = "2026-08-14T16:12:17.503Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1e/51/3fb9e65ae76ee97bd611869a503fa3fc0a6e81dd8b737cf3003f682df7ff/orjson-3.11.9-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f01c4818b3fc9b0da8e096722a84318071eaa118df35f6ed2344da0e73a5444f", size = 228522, upload-time = "2026-05-06T15:09:35.362Z" },
|
{ url = "https://files.pythonhosted.org/packages/e2/f4/1e82aa2efc9916422d804697876ce433c907a1abd7c7e5c6d3d48565e5f9/orjson-3.12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dce0166feb0a737ab84f598c9a338cbc0b764a036617aa686194f53c7eba0c3e", size = 130891, upload-time = "2026-08-14T16:12:18.762Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/fa/9d54b07cb3f3b0bfd57841478e42d7a0ece4a9f49f9907eecf5a45461687/orjson-3.11.9-cp311-cp311-macosx_15_0_arm64.whl", hash = "sha256:3ebca4179031ee716ed076ffadc29428e900512f6fccee8614c9983157fcf19c", size = 128463, upload-time = "2026-05-06T15:09:37.063Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/e1/15169e9d22b59a406264f99d6db387c0b0b12b6357a8a0169917c2a713eb/orjson-3.12.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9caf3d09f47c3c70c4451ada20ef9bc4a4cdffa26f49862cf0a253b329aae2d5", size = 131285, upload-time = "2026-08-14T16:12:20.251Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/88/b1/6ceafc2eefd0a553e3be77ce6c49d107e772485d9568629376171c50e634/orjson-3.11.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48ee05097750de0ff69ed5b7bbcf0732182fd57a24043dcc2a1da780a5ead3a5", size = 132306, upload-time = "2026-05-06T15:09:38.299Z" },
|
{ url = "https://files.pythonhosted.org/packages/a4/3a/763dbd426290d044ec3e615a05e70adb6d8b6f95bf17dc355c0081a5e8b6/orjson-3.12.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b9dca132b1fda5565088e65a6b6e742285e0aeceb6fae549fa8863e16c7d3998", size = 135707, upload-time = "2026-08-14T16:12:21.652Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ea/76/f11311285324a40aab1e3031385c50b635a7cd0734fdaf60c7e89a696f60/orjson-3.11.9-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a6082706765a95a6680d812e1daf1c0cfe8adec7831b3ff3b625693f3b461b1c", size = 127988, upload-time = "2026-05-06T15:09:39.597Z" },
|
{ url = "https://files.pythonhosted.org/packages/04/d1/3b2038ed168d22e14182ed715d6963f9c073a83a2ba43cfe918a4fc43c64/orjson-3.12.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a791f793b287bbc135b8e87c34e35c8bfc693e2a8a620fab1ae682b925f9a32e", size = 127669, upload-time = "2026-08-14T16:12:22.926Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9e/85/0ef63bcf1337f44031ce9b91b1919563f62a37527b3ea4368bb15a22e5d7/orjson-3.11.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:277fefe9d76ee17eb14debf399e3533d4d63b5f677a4d3719eb763536af1f4bd", size = 135188, upload-time = "2026-05-06T15:09:40.957Z" },
|
{ url = "https://files.pythonhosted.org/packages/88/ae/b84b3d3e65f5629ada0edcb1d2bccc55d7c5f89d8b981537ecdc3d6f31ec/orjson-3.12.0-cp311-cp311-win32.whl", hash = "sha256:31ed278a36304390adc3eec5d7f6fd593a7c3e99e5a06cd07866396c4b1b4710", size = 128043, upload-time = "2026-08-14T16:12:24.367Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/05/94/b0d27090ea8a2095db3c2bd1b1c96f96f19bbb494d7fef33130e846e613d/orjson-3.11.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:03db380e3780fa0015ed776a90f20e8e20bb11dde13b216ce19e5718e3dfba62", size = 145937, upload-time = "2026-05-06T15:09:42.249Z" },
|
{ url = "https://files.pythonhosted.org/packages/35/24/2ed0e6f51ea3d0af45d807233a851175af75bec83ef5fd0d6a2601904ec0/orjson-3.12.0-cp311-cp311-win_amd64.whl", hash = "sha256:fb2539159dfe8d371914f354360fa50e4a577cc89222a3828b9650a5e5040252", size = 122084, upload-time = "2026-08-14T16:12:25.813Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/09/eb/75d50c29c05b8054013e221e598820a365c8e64065312e75e202ed880709/orjson-3.11.9-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33d7d766701847dc6729846362dc27895d2f2d2251264f9d10e7cb9878194877", size = 132758, upload-time = "2026-05-06T15:09:43.945Z" },
|
{ url = "https://files.pythonhosted.org/packages/21/dd/95d25fcfbc9471799ef6bb01c552d64ee5cde93ee40ba2f423dd3442c708/orjson-3.12.0-cp311-cp311-win_arm64.whl", hash = "sha256:61318b6de893c7a9d9f3e5ecbadccbfc26a7eb417ccc7bbf0771de3b4d72f868", size = 127035, upload-time = "2026-08-14T16:12:27.201Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/49/bd/360686f39348aa88827cb6fbf7dc606fd41c831a35235e1abf1db8e3a9e6/orjson-3.11.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:147302878da387104b66bb4a8b0227d1d487e976ce41a8501916161072ed87b1", size = 133971, upload-time = "2026-05-06T15:09:45.239Z" },
|
{ url = "https://files.pythonhosted.org/packages/be/4a/295da39c651c2faac8bd351a2a346f0fdedd9d50b847ee9dfc27d2207ef6/orjson-3.12.0-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:aa3e43a6846e91d7bde3d5a9c66090fcd8744f569a9b6cffc5e1ca38f6a461c0", size = 223427, upload-time = "2026-08-14T16:12:28.525Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/30/3178eb16f3221aeef068b6f1f1ebe05f656ea5c6dffe9f6c917329fe17a3/orjson-3.11.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3513550321f8c8c811a7c3297b8a630e82dc08e4c10216d07703c997776236cd", size = 141685, upload-time = "2026-05-06T15:09:46.858Z" },
|
{ url = "https://files.pythonhosted.org/packages/29/98/758cf90fbeaaafb7f8141bfac75a432099959f3a2f5db93a412e876415d8/orjson-3.12.0-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:11edb4660a6680abee9788a3a9072208a2c96538cc1322bd79542065229d8e54", size = 123725, upload-time = "2026-08-14T16:12:30.013Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/f1/ff2f19ed0225f9680fafa42febca3570dd59444ebf190980738d376214c2/orjson-3.11.9-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c5d001196b89fa9cf0a4ab79766cd835b991a166e4b621ba95089edc50c429ff", size = 415167, upload-time = "2026-05-06T15:09:48.312Z" },
|
{ url = "https://files.pythonhosted.org/packages/32/b5/5b934d251f8651f7e41df180ad0c57a6e1cabe15c7bd331638413a50ebc9/orjson-3.12.0-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:2d3a9da945a4d96ae758fdaaca56742e6b73b6fd554c5d8876f252a6dad70b83", size = 113375, upload-time = "2026-08-14T16:12:31.209Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9b/61/863bddf0da6e9e586765414debd54b4e58db05f560902b6d00658cb88636/orjson-3.11.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:16969c9d369c98eb084889c6e4d2d39b77c7eb38ceccf8da2a9fff62ae908980", size = 147913, upload-time = "2026-05-06T15:09:49.733Z" },
|
{ url = "https://files.pythonhosted.org/packages/cd/d2/37efb5b12a176ce3ced29f4144f20da57d02757f78ce549637dc1b4e1fc8/orjson-3.12.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:92ffc09e07233a6ab6d4e067f7841edcbcc134cb4812155cf171ea5255a421d7", size = 129983, upload-time = "2026-08-14T16:12:32.721Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b6/8a/4081492586d75b073d60c5271a8d0f05a0955cabf1e34c8473f6fcd84235/orjson-3.11.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:63e0efbc991250c0b3143488fa57d95affcabbfc63c99c48d625dd37779aafe2", size = 136959, upload-time = "2026-05-06T15:09:51.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/50/22/0644b87c73f13e0092df8f35a1fe280d991e5e90072087411e0dd7e44e0c/orjson-3.12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf44e374aadde77b1f6109f1030be51433eb61984379852766b6f4e187db7b1e", size = 130629, upload-time = "2026-08-14T16:12:34.084Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/bd/70b6ab193594d7abb875320c0a7c8335e846f28968c432c31042409c3c8d/orjson-3.11.9-cp311-cp311-win32.whl", hash = "sha256:14ed654580c1ed2bc217352ec82f91b047aef82951aa71c7f64e0dcb03c0e180", size = 131533, upload-time = "2026-05-06T15:09:52.637Z" },
|
{ url = "https://files.pythonhosted.org/packages/8c/57/80b986ebfecd9c6a177ddf1c2319717f0cd8feffb2b78946595a18a2fc88/orjson-3.12.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1192a7021b6d071aaf909864f6e924d6a2675ca360485b972b8401749311750b", size = 131245, upload-time = "2026-08-14T16:12:35.713Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3f/17/1a1a228183d62d1b77e2c30d210f47dd4768b310ebe1607c63e3c0e3a71e/orjson-3.11.9-cp311-cp311-win_amd64.whl", hash = "sha256:57ea77fb70a448ce87d18fca050193202a3da5e54598f6501ca5476fb66cfe02", size = 127106, upload-time = "2026-05-06T15:09:54.204Z" },
|
{ url = "https://files.pythonhosted.org/packages/80/3d/75c5ac5a69161f44492a68fbdde66f4cc4ce48cd5e1fb05918e46f0c8848/orjson-3.12.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:53c0c474a9d9aff9aebfc0c88de1f28f843d940e6e3a80729abdf6a20274356f", size = 135397, upload-time = "2026-08-14T16:12:37.128Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b8/95/285de5fa296d09681ee9c546cd4a8aeb773b701cf343dc125994f4d52953/orjson-3.11.9-cp311-cp311-win_arm64.whl", hash = "sha256:19b72ed11572a2ee51a67a903afbe5af504f84ed6f529c0fe44b0ab3fb5cc697", size = 126848, upload-time = "2026-05-06T15:09:55.551Z" },
|
{ url = "https://files.pythonhosted.org/packages/71/93/4d71f2df314a97ff0d27a4559bf5888fc8406e3c6dec90e92291e3511215/orjson-3.12.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:532ff8cd4bd59a327a953a7dcde922c7fc25b85e29721bb8633265430d3a3873", size = 127693, upload-time = "2026-08-14T16:12:38.627Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/6d/11867a3ffa3a3608d84a4de51ef4dd0896d6b5cc9132fbe1daf593e677bc/orjson-3.11.9-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9ef6fe90aadef185c7b128859f40beb24720b4ecea95379fc9000931179c3a49", size = 228515, upload-time = "2026-05-06T15:09:57.265Z" },
|
{ url = "https://files.pythonhosted.org/packages/bc/1d/0dbc6be5adfd1730491072fb60beb6bcdf5d7b2596ee41b7fc2e298bfc09/orjson-3.12.0-cp312-cp312-win32.whl", hash = "sha256:a6cf4b18e7de173f209f2084ffbd736dd72389a396326ee80a7022168be232e5", size = 128000, upload-time = "2026-08-14T16:12:39.954Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/75/05912954c8b288f34fcf5cd4b9b071cb4f6e77b9961e175e56ebb258089f/orjson-3.11.9-cp312-cp312-macosx_15_0_arm64.whl", hash = "sha256:e5c9b8f28e726e97d97696c826bc7bea5d71cecd63576dba92924a32c1961291", size = 128409, upload-time = "2026-05-06T15:09:59.063Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/c9/97b1ce0112ebf5e949c775ed5b1755e562233179f3584579673cc24d6378/orjson-3.12.0-cp312-cp312-win_amd64.whl", hash = "sha256:010811c1b69773450a01cef97727a67b223242f350b77d4ca000e59a9ef2155a", size = 122106, upload-time = "2026-08-14T16:12:41.324Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ab/86/1c3a47df3bc8191ea9ac51603bbb872a95167a364320c269f2557911f406/orjson-3.11.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26a473dbb4162108b27901492546f83c76fdcea3d0eadff00ae7a07e18dcce09", size = 132106, upload-time = "2026-05-06T15:10:00.798Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/6a/facd8b312e4a0d3a7fa978c7e15821f74a336adf1d65529faec33b48e18b/orjson-3.12.0-cp312-cp312-win_arm64.whl", hash = "sha256:ad29eece0c601737f2a60edc2752a84e7a0785df3efb62e3012834700a5afe0d", size = 126869, upload-time = "2026-08-14T16:12:42.651Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/cf/b33b5f3e695ae7d63feef9d915c37cc3b8f465493dcd4f8e0b4c697a2366/orjson-3.11.9-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:011382e2a60fda9d46f1cdee31068cfc52ffe952b587d683ec0463002802a0f4", size = 127864, upload-time = "2026-05-06T15:10:02.15Z" },
|
{ url = "https://files.pythonhosted.org/packages/54/cb/d7b78218a987eb8a8ce4eeae0286b1bb679333eb631ea0eeaf6371680bfc/orjson-3.12.0-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9a36ec60f1796f9a3f13e3b98390295e17a1c7c10155b448d264098bf9ee5900", size = 223397, upload-time = "2026-08-14T16:12:44.003Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/6a/6cf69385a58208024fcb8c014e2141b8ce838aba6492b589f8acfff97fab/orjson-3.11.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c2d3dc759490128c5c1711a53eeaa8ee1d437fd0038ffd2b6008abf46db3f882", size = 135213, upload-time = "2026-05-06T15:10:03.515Z" },
|
{ url = "https://files.pythonhosted.org/packages/f8/4a/bc87c45e7ec639d35ebefd62618e01939531ac8e171426606a01bda05914/orjson-3.12.0-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:ad0422b92d5195443a39f80c3bcf731cc2e00f153bd32063a47b73b057bd0f03", size = 123662, upload-time = "2026-08-14T16:12:45.433Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/f8/0b1bd3e8f2efcdd376af5c8cfd79eaf13f018080c0089c80ebd724e3c7fb/orjson-3.11.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d8ea516b3726d190e1b4297e6f4e7a8650347ae053868a18163b4dd3641d1fff", size = 145994, upload-time = "2026-05-06T15:10:05.083Z" },
|
{ url = "https://files.pythonhosted.org/packages/94/ee/c9a4ff3f2dbedbbe9e635d0fa72c8866adede09b6335ef9644f53752f0d8/orjson-3.12.0-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:5a0fdbc216388f653d3752ff310e710f59253bd4ed6a2bfb3f4f06b84714bbd8", size = 113374, upload-time = "2026-08-14T16:12:46.755Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/59/dab79f61044c529d2c81aecdc589b1f833a1c8dec11ba3b1c2498a02ca7e/orjson-3.11.9-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:380cdce7ba24989af81d0a7013d0aaec5d0e2a21734c0e2681b1bc4f141957fe", size = 132744, upload-time = "2026-05-06T15:10:06.853Z" },
|
{ url = "https://files.pythonhosted.org/packages/75/09/3f330a026a796c8b4c97a6f429652a5e912e7065039bf96ed25e42aa7b25/orjson-3.12.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:2eb5c56e534127b2b8fa38d2363c8b1b8190367ee0d1d16c041517d880843b94", size = 130029, upload-time = "2026-08-14T16:12:48.06Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0e/a4/82b7a2fe5d8a67a59ed831b24d59a3d46ea7d207b66e1602d376541d94a6/orjson-3.11.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4fa4f0af7fa18951f7ab3fc2148e223af211bf03f59e1c6034ec3f97f21d61", size = 134014, upload-time = "2026-05-06T15:10:08.213Z" },
|
{ url = "https://files.pythonhosted.org/packages/7d/40/094cc53126a3d22f76cdf83b6ea67338bed01d774037621a785aa8e6e5ea/orjson-3.12.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784106539f4b9d4b930e0b4eb8d45168507dae001945e71b4675a367f1e5e806", size = 130528, upload-time = "2026-08-14T16:12:49.362Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/50/c7/375e83a76851b73b2e39f3bcf0e5a19e2b89bad13e5bca97d0b293d27f24/orjson-3.11.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a8f5f8bc7ce7d59f08d9f99fa510c06496164a24cb5f3d34537dbd9ca30132e2", size = 141509, upload-time = "2026-05-06T15:10:09.595Z" },
|
{ url = "https://files.pythonhosted.org/packages/bc/74/89bb236deb9565f99434b13052bb40ddfcce4adf3afbfa3132ee7e421468/orjson-3.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c680706fc8396d95e7c4c1f9482563f552137aef91b57237a3ad5aaf64629df", size = 131075, upload-time = "2026-08-14T16:12:50.692Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/7c/49d5d82a3d3097f641f094f552131f1e2723b0b8cb0fa2874ab65ecfffa6/orjson-3.11.9-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:4d7fde5501b944f83b3e665e1b31343ff6e154b15560a16b7130ea1e594a4206", size = 415127, upload-time = "2026-05-06T15:10:11.049Z" },
|
{ url = "https://files.pythonhosted.org/packages/0c/ac/1176360d762c01b5bd34acd56fc098e936c491363d8b6b397ad4aa475547/orjson-3.12.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:83445adc40cba26d6d621185a45128ce455b766af368cad2ab64b970603a7978", size = 135321, upload-time = "2026-08-14T16:12:52.114Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3a/dc/7446c538590d55f455647e5f3c61fc33f7108714e7afcffa6a2a033f8350/orjson-3.11.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cde1a448023ba7d5bb4c01c5afb48894380b5e4956e0627266526587ef4e535f", size = 148025, upload-time = "2026-05-06T15:10:12.842Z" },
|
{ url = "https://files.pythonhosted.org/packages/7a/02/bbd881c8b9276d50b998de38b4e97de8ace1aac940b0ee545aedbf65ed00/orjson-3.12.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:644d005bc82f917337a95ce270c9f6f92f9834c2bed7b1477572f8db00784222", size = 127472, upload-time = "2026-08-14T16:12:53.517Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/df/e5/4d2d8af06f788329b4f78f8cc3679bb395392fcaa1e4d8d3c33e85308fa4/orjson-3.11.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:71e63adb0e1f1ed5d9e168f50a91ceb93ae6420731d222dc7da5c69409aa47aa", size = 136943, upload-time = "2026-05-06T15:10:14.405Z" },
|
{ url = "https://files.pythonhosted.org/packages/8e/02/a0934d7503e6dcbedd6afac3e7f3f8597fd09389949ad94d0f7540e9dbca/orjson-3.12.0-cp313-cp313-win32.whl", hash = "sha256:d8e78d3d93705e3d27cc17cdb209e44d7a8ea203010cac6ce9c7ffc1ae1996f1", size = 128000, upload-time = "2026-08-14T16:12:55.14Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/69/850264ccf6d80f6b174620d30a87f65c9b1490aba33fe6b62798e618cad3/orjson-3.11.9-cp312-cp312-win32.whl", hash = "sha256:2d057a602cdd19a0ad680417527c45b6961a095081c0f46fe0e03e304aac6470", size = 131606, upload-time = "2026-05-06T15:10:15.791Z" },
|
{ url = "https://files.pythonhosted.org/packages/52/87/69f98f8d40faff103a965a5fbb83f08241b01beaf92badb5413fbc9358cc/orjson-3.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:b85931be5b6763c31283805c9bdaae1ca03ad9f6f12a15f1cbf6745b907932c2", size = 121841, upload-time = "2026-08-14T16:12:56.507Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b9/d5/973a43fc9c55e20f2051e9830997649f669be0cb3ca52192087c0143f118/orjson-3.11.9-cp312-cp312-win_amd64.whl", hash = "sha256:59e403b1cc5a676da8eaf31f6254801b7341b3e29efa85f92b48d272637e77be", size = 127101, upload-time = "2026-05-06T15:10:17.129Z" },
|
{ url = "https://files.pythonhosted.org/packages/e6/07/b83046a4e3cadcc0987d0f160696107c4af706a619b56e4ad01940cadadf/orjson-3.12.0-cp313-cp313-win_arm64.whl", hash = "sha256:6a31348d7dfa64cd9c78bd1f510ff44c48fe64d71094e6b90e364dba3b55949e", size = 126765, upload-time = "2026-08-14T16:12:57.806Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/ae/495470f0e4a18f73fa10b7f6b84b464ec4cc5291c4e0c7c2a6c400bef006/orjson-3.11.9-cp312-cp312-win_arm64.whl", hash = "sha256:9af678d6488357948f1f84c6cd1c1d397c014e1ae2f98ae082a44eb48f602624", size = 126736, upload-time = "2026-05-06T15:10:18.645Z" },
|
{ url = "https://files.pythonhosted.org/packages/12/9d/3931253e6f3148abf2cbe14830367042a4806b362ea520df2303db188fb9/orjson-3.12.0-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9e6fee342a48760e854d743e7a81534d8e2925a6f46e09f750cf56b50fd1de5d", size = 223391, upload-time = "2026-08-14T16:12:59.184Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/32/33/93fcc25907235c344ae73122f8a4e01d2d393ef062b4af7d2e2487a32c37/orjson-3.11.9-cp313-cp313-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:4bab1b2d6141fe7b32ae71dac905666ece4f94936efbfb13d55bb7739a3a6021", size = 228458, upload-time = "2026-05-06T15:10:20.079Z" },
|
{ url = "https://files.pythonhosted.org/packages/8a/0e/b4a4f1e305367245877b967a0bad70fcf001d77c54ac4339a120b66fdae4/orjson-3.12.0-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:8c3bb86dd10f39b3fbf434b7d5dc7cac77d6fc8ac572ae30a10731ede2c4b647", size = 123659, upload-time = "2026-08-14T16:13:00.548Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8f/27/b1e6dadb3c080313c03fdd8067b85e6a0460c7d8d6a1c3984ef77b904e4d/orjson-3.11.9-cp313-cp313-macosx_15_0_arm64.whl", hash = "sha256:844417969855fc7a41be124aafe83dc424592a7f77cd4501900c67307122b92c", size = 128368, upload-time = "2026-05-06T15:10:21.549Z" },
|
{ url = "https://files.pythonhosted.org/packages/96/f3/6782c6fa85e2702bc66be183c3b421486167dcf266ee4dc1403fe3824870/orjson-3.12.0-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.whl", hash = "sha256:2bb3ce43203936072dd8b4917b01d3aecfc02329bfb42510cb7cfb24708adc9c", size = 113337, upload-time = "2026-08-14T16:13:02.009Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/21/0f/c9ede0bf052f6b4051e64a7d4fa91b725cccf8321a6a786e86eb03519f00/orjson-3.11.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ffe02797b5e9f3a9d8292ddcd289b474ad13e81ad83cd1891a240811f1d2cb81", size = 132070, upload-time = "2026-05-06T15:10:23.371Z" },
|
{ url = "https://files.pythonhosted.org/packages/bf/79/b32ab64bacda9d0fa4942ef483bd03cabf0eaf2be819ca9fb7ff610c559d/orjson-3.12.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.whl", hash = "sha256:6a2a79c89984dc719817d388c8709e0efc2a2795a934eaa746b4882eb6045adc", size = 130112, upload-time = "2026-08-14T16:13:03.404Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fd/26/d398e28048dc18205bbe812f2c88cb9b40313db2470778e25964796458fe/orjson-3.11.9-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0e4eed3b200023042814d2fc8a5d2e880f13b52e1ed2485e83da4f3962f7dc1a", size = 127892, upload-time = "2026-05-06T15:10:24.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/49/6e6142999ca01509219be5e5a9c338a3e5ea011f63e91ff473fbbf3734ed/orjson-3.12.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f06dd838d1e07d9b1de0932ec0485ec92c4d5f5d1ad4817a656268c3e88be1e1", size = 130520, upload-time = "2026-08-14T16:13:04.798Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/60/52b0054c4c700d5aa7fc5b7ca96917400d8f061307778578e67a10e25852/orjson-3.11.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8aff7da9952a5ad1cef8e68017724d96c7b9a66e99e91d6252e1b133d67a7b10", size = 135217, upload-time = "2026-05-06T15:10:26.084Z" },
|
{ url = "https://files.pythonhosted.org/packages/49/d0/3745af0a4cc9867784f29722929cec4d10bd1c877cd754b01ba6d96eb21a/orjson-3.12.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c6b11be792c3d2c6a4be2af4ebf97a68d0bf5f580aca6e86a418a354f6cc846a", size = 131053, upload-time = "2026-08-14T16:13:06.14Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d5/97/1e3dc2b2a28b7b2528f403d2fc1d79ec5f39af3bc143ab65d3ec26426385/orjson-3.11.9-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4d4e98d6f3b8afed8bc8cd9718ec0cdf46661826beefb53fe8eafb37f2bf0362", size = 145980, upload-time = "2026-05-06T15:10:28.062Z" },
|
{ url = "https://files.pythonhosted.org/packages/c3/f4/6fe5a22fa478fffb190e65c338c84df5c311ef597b363150a17cc57063c0/orjson-3.12.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:477ecaf6b9f88f873341b91fcc736119ca81b5e002a9f7f308ff5b4f2ce2a70e", size = 135321, upload-time = "2026-08-14T16:13:07.544Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fc/39/31fbfe7850f2de32dee7e7e5c09f26d403ab01e440ac96001c6b01ad3c99/orjson-3.11.9-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3a81d52442a7c99b3662333235b3adf96a1715864658b35bb797212be7bddb97", size = 132738, upload-time = "2026-05-06T15:10:29.727Z" },
|
{ url = "https://files.pythonhosted.org/packages/ff/41/b1b0ec30289646a81a76e2dbaae2686b96fcccb7cb0323dc1dd78cbc7875/orjson-3.12.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:f3c0683136acdc29afdf88a5bc2f7d3d0e34087788d1d63c0144b805a87a196f", size = 127485, upload-time = "2026-08-14T16:13:08.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a1/08/dca0082dd2a194acb93e5457e73455388e2e2ca464a2672449a9ddbb679d/orjson-3.11.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e39364e726a8fff737309aff059ff67d8a8c8d5b677be7bb49a8b3e84b7e218", size = 134033, upload-time = "2026-05-06T15:10:31.152Z" },
|
{ url = "https://files.pythonhosted.org/packages/bf/2b/277404bdcc21c93b112b963655b76443ebfe828f8a3ff1de7d90f8850eb3/orjson-3.12.0-cp314-cp314-win32.whl", hash = "sha256:d39f3f5c3927e2dc0913fe5bbc1a2f6b1b9d1bba1de6358340d0ad0d0c00ca92", size = 128048, upload-time = "2026-08-14T16:13:10.305Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/11/d4/5bdb0626801230139987385554c5d4c42255218ac906525bf4347f22cd95/orjson-3.11.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4fd66214623f1b17501df9f0543bef0b833979ab5b6ded1e1d123222866aa8c9", size = 141492, upload-time = "2026-05-06T15:10:32.641Z" },
|
{ url = "https://files.pythonhosted.org/packages/41/2b/395b36fa2b4ce7af70b651d715e88f80d884b2c2b14a6b53e84d554fb5f0/orjson-3.12.0-cp314-cp314-win_amd64.whl", hash = "sha256:0b1ac5bf6609b2716c7954011c5fef6254922df029f45d032ee4ebf5d363cbed", size = 121858, upload-time = "2026-08-14T16:13:11.634Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/88/a21fb53b3ede6703aede6dce4710ed4111e5b201cfa6bbff5e544f9d47d7/orjson-3.11.9-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:8ecc30f10465fa1e0ce13fd01d9e22c316e5053a719a8d915d4545a09a5ff677", size = 415087, upload-time = "2026-05-06T15:10:34.438Z" },
|
{ url = "https://files.pythonhosted.org/packages/ea/a3/833e895ff452859eebe75093d26691fe9108f1a7a6a08435d7a5780ea652/orjson-3.12.0-cp314-cp314-win_arm64.whl", hash = "sha256:50fae885cb073eac7556353ff3df93312b0d5137b0a5056b2bb63f97ed9a93c7", size = 126749, upload-time = "2026-08-14T16:13:13.117Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/3d/57/1b30daf70f0d8180e9a73cefbfbdd99e4bf19eb020466502b01fba7e0e50/orjson-3.11.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:97db4c94a7db398a5bd636273324f0b3fd58b350bbbac8bb380ceb825a9b40f4", size = 148031, upload-time = "2026-05-06T15:10:36.358Z" },
|
{ url = "https://files.pythonhosted.org/packages/58/64/99c8947ece10c17176af9aae85c4948f1d109da77440ec14d87239efaf73/orjson-3.12.0-cp315-cp315-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:01efac2074fffb4cb1ea3fab7861e9d0f2a26913854a972f5ac760525dbdaf6e", size = 223398, upload-time = "2026-08-14T16:13:14.694Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/04/83/45fbb6d962e260807f99441db9613cee868ceda4baceda59b3720a563f97/orjson-3.11.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9f78cf8fec5bd627f4082b8dfeac7871b43d7f3274904492a43dab39f18a19a0", size = 136915, upload-time = "2026-05-06T15:10:38.013Z" },
|
{ url = "https://files.pythonhosted.org/packages/3e/30/cf983fe09f2731420fda097a9f7ef4343f47fa216c228961ad8f6da44f3d/orjson-3.12.0-cp315-cp315-macosx_15_0_arm64.whl", hash = "sha256:ed4ca42bd55955aa34deedcfdfd0e0c31abf51143aae158ae2bc3520b626e517", size = 123655, upload-time = "2026-08-14T16:13:16.221Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/cc/2d10025f9056d376e4127ec05a5808b218d46f035fdc08178a5411b34250/orjson-3.11.9-cp313-cp313-win32.whl", hash = "sha256:d4087e5c0209a0a8efe4de3303c234b9c44d1174161dcd851e8eea07c7560b32", size = 131613, upload-time = "2026-05-06T15:10:39.569Z" },
|
{ url = "https://files.pythonhosted.org/packages/11/50/9cb8ae73fa4749dbbc20f617004213b5ff01c20aaeec34c3f31124f2c1d8/orjson-3.12.0-cp315-cp315-manylinux_2_39_aarch64.whl", hash = "sha256:40f92192227505acca4e2533ce565f8e6b9535f7d0d09b0968452f18b7376b38", size = 130515, upload-time = "2026-08-14T16:13:17.601Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/67/bd/2775ff28bfe883b9aa1ff348300542eb2ef1ee18d8ae0e3a49846817a865/orjson-3.11.9-cp313-cp313-win_amd64.whl", hash = "sha256:051b102c93b4f634e89f3866b07b9a9a98915ada541f4ec30f177067b2694979", size = 127086, upload-time = "2026-05-06T15:10:41.262Z" },
|
{ url = "https://files.pythonhosted.org/packages/9f/0a/adb6ce1a5b5fbf9cb1790f9961bb668a0dd5429aadaf6cee044724681795/orjson-3.12.0-cp315-cp315-manylinux_2_39_armv7l.whl", hash = "sha256:33efefcf5d88eaf400b47e2eba02f91f319bb9951be61ca500b7d536d3f2079d", size = 113327, upload-time = "2026-08-14T16:13:18.927Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/91/2b/d26799e580939e32a7da9a39531bc9e58e15ca32ffaa6a8cb3e9bb0d22cd/orjson-3.11.9-cp313-cp313-win_arm64.whl", hash = "sha256:cce9127885941bd28f080cecf1f1d288336b7e0d812c345b08be88b572796254", size = 126696, upload-time = "2026-05-06T15:10:42.651Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/5c/d17f61581d8dbdde7048f87a330fa24915edec38db4d72b381fec14fbb56/orjson-3.12.0-cp315-cp315-manylinux_2_39_i686.whl", hash = "sha256:8e386b0bc0ddd7cd2056f884b5a0af33592bd01ac66a7ca4b42a65a7e7774a13", size = 130105, upload-time = "2026-08-14T16:13:20.317Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8e/eb/5da01e356015aee6ecfa1187ced87aef51364e306f5e695dd52719bf0e78/orjson-3.11.9-cp314-cp314-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:b6ef1979adc4bc243523f1a2ba91418030a8e29b0a99cbe7e0e2d6807d4dce6e", size = 228465, upload-time = "2026-05-06T15:10:44.097Z" },
|
{ url = "https://files.pythonhosted.org/packages/9f/b7/938befcf33bee4704a92ecec6a2731224c539d939bf9429fd39396d28931/orjson-3.12.0-cp315-cp315-manylinux_2_39_x86_64.whl", hash = "sha256:58c58e1de0006ffb580368d6793c36c7b0b021db066479cf281bf5061e732328", size = 131049, upload-time = "2026-08-14T16:13:21.719Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/64/62/3e0e0c14c957133bcd855395c62b55ed4e3b0af23ffea11b032cb1dcbdb1/orjson-3.11.9-cp314-cp314-macosx_15_0_arm64.whl", hash = "sha256:f36b7f32c7c0db4a719f1fc5824db4a9c6f8bd1a354debb91faf26ebf3a4c71e", size = 128364, upload-time = "2026-05-06T15:10:45.839Z" },
|
{ url = "https://files.pythonhosted.org/packages/b0/15/cfa2021d64d5aa8bb5c9f604ef375e00ec8b657651b5dd650b1b7ad13df1/orjson-3.12.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:08231552159be266a7269555bd9f7c016aee7d9ad6dab06eb58796c5ccb7101c", size = 135320, upload-time = "2026-08-14T16:13:23.415Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/5a/07d8aa117211a8ed7630bda80c8c0b14d04e0f8dcf99bcf49656e4a710eb/orjson-3.11.9-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:08f4d8ebb44925c794e535b2bebc507cebf32209df81de22ae285fb0d8d66de0", size = 132063, upload-time = "2026-05-06T15:10:47.267Z" },
|
{ url = "https://files.pythonhosted.org/packages/1a/50/3e75dfe357c1e8f9e287c7a5740260ef15bd23a5299eae8d0835dcad5375/orjson-3.12.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:a15f9a891bce5f5cc5d210e3ad8614d4d1b489a56448c099d6d2a7168b2d954a", size = 127488, upload-time = "2026-08-14T16:13:24.791Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d6/ec/4acaf21483e18aa945be74a474c74b434f284b549f275a0a39b9f98956e9/orjson-3.11.9-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6cc7923789694fd58f001cbcac7e47abc13af4d560ebbfcf3b41a8b1a0748124", size = 122356, upload-time = "2026-05-06T15:10:48.765Z" },
|
{ url = "https://files.pythonhosted.org/packages/11/a6/79aed402eb3ab284dc5b4791a7ad62c5875127de01b8e3f04bd92d551298/orjson-3.12.0-cp315-cp315-win32.whl", hash = "sha256:03091c8a64db4be38746597ceea68f33c238e27acd9bfe99fb59420224ae7a55", size = 128048, upload-time = "2026-08-14T16:13:26.217Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d8/5f0555e7638801323b7a75850f92e7dfa891bc84fe27a1ba4449170d1200/orjson-3.11.9-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea5c46eb2d3af39e806b986f4b09d5c2706a1f5afde3cbf7544ce6616127173c", size = 129592, upload-time = "2026-05-06T15:10:50.13Z" },
|
{ url = "https://files.pythonhosted.org/packages/64/f7/2723e264aab7248c1ed6ecaad8e5d0cb866c0cffde75442102ffa7491aba/orjson-3.12.0-cp315-cp315-win_amd64.whl", hash = "sha256:2b7bcefb9f40fa242fa6b06377232c048e655747790829609168c01162f60578", size = 121860, upload-time = "2026-08-14T16:13:27.577Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b6/30/ed9860412a3603ceb3c5955bfd72d28b9d0e7ba6ed81add14f83d7114236/orjson-3.11.9-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f5d89a2ed90731df3be64bab0aa44f78bff39fdc9d71c291f4a8023aa46425b7", size = 140491, upload-time = "2026-05-06T15:10:51.582Z" },
|
{ url = "https://files.pythonhosted.org/packages/82/56/630c9113ec8996778f1f0304b364b091b9a9db5fef5fdc17cca622f5ea24/orjson-3.12.0-cp315-cp315-win_arm64.whl", hash = "sha256:859fc4196855890150bb08e649b30d2c93b249b3e3edd0d3bb2231abf8aa8adc", size = 126754, upload-time = "2026-08-14T16:13:28.962Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d0/17/adc514dea7ac7c505527febf884934b815d34f0c7b8693c1a8b39c5c4a57/orjson-3.11.9-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:25e4aed0312d292c09f61af25bba34e0b2c88546041472b09088c39a4d828af1", size = 127309, upload-time = "2026-05-06T15:10:53.329Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/3e/c0b690253f0b82d86e99949af13533363acfb5432ecb5d53dd5b3bce9c34/orjson-3.11.9-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aaea64f3f467d22e70eeed68bdccb3bc4f83f650446c4a03c59f2cba28a108db", size = 134030, upload-time = "2026-05-06T15:10:54.988Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/c1/7a/bc82a0bb25e9faaf92dc4d9ef002732efc09737706af83e346788641d4a7/orjson-3.11.9-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a028425d1b440c5d92a6be1e1a020739dfe67ea87d96c6dbe828c1b30041728b", size = 141482, upload-time = "2026-05-06T15:10:56.663Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/01/55/e69188b939f77d5d32a9833745ace31ea5ccae3ab613a1ec185d3cd2c4fb/orjson-3.11.9-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:5b192c6cf397e4455b11523c5cf2b18ed084c1bbd61b6c0926344d2129481972", size = 415178, upload-time = "2026-05-06T15:10:58.446Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/2e/1a/b8a5a7ac527e80b9cb11d51e3f6689b709279183264b9ec5c7bc680bb8b5/orjson-3.11.9-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ea407d4ccf5891d667d045fecae97a7a1e5e87b3b97f97ae1803c2e741130be0", size = 148089, upload-time = "2026-05-06T15:11:00.441Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/97/4e/00503f64204bf859b37213a63927028f30fb6268cd8677fb0a5ad48155e1/orjson-3.11.9-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5f63aaf97afd9f6dec5b1a68e1b8da12bfccb4cb9a9a65c3e0b6c847849e7586", size = 136921, upload-time = "2026-05-06T15:11:02.176Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/ba/a23b82a0a8d0ed7bed4e5f5035aae751cad4ff6a1e8d2ecd14d8860f5929/orjson-3.11.9-cp314-cp314-win32.whl", hash = "sha256:e30ab17845bb9fa54ccf67fa4f9f5282652d54faa6d17452f47d0f369d038673", size = 131638, upload-time = "2026-05-06T15:11:03.696Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/c3/0c6798456bade745c75c452342dabacce5798196483e77e643be1f53877d/orjson-3.11.9-cp314-cp314-win_amd64.whl", hash = "sha256:32ef5f4283a3be81913947d19608eacb7c6608026851123790cd9cc8982af34b", size = 127078, upload-time = "2026-05-06T15:11:05.123Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/16/21/5a3f1e8913103b703a436a5664238e5b965ec392b555fe68943ea3691e6b/orjson-3.11.9-cp314-cp314-win_arm64.whl", hash = "sha256:eebdbdeef0094e4f5aefa20dcd4eb2368ab5e7a3b4edea27f1e7b2892e009cf9", size = 126687, upload-time = "2026-05-06T15:11:06.602Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -957,27 +979,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.20"
|
version = "0.16.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/85/c8e12473c93018f92d19dd988a294202e1c27426c47ec4de53ffb847b8d8/ruff-0.16.5.tar.gz", hash = "sha256:1b88500f9ffbcab3dedb0082c9f9492e91ec3d618aac1236a3e0189938f7040b", size = 4912003, upload-time = "2026-08-27T16:34:18.258Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/b6/77c90a970fe2dae17a723acbd011043ea97c98d7deacccefdc4ba74ec512/ruff-0.16.5-py3-none-linux_armv6l.whl", hash = "sha256:12e5f673e774c35fbb62f288809c7653b73445f8ecec6b6063fd6ea3521aa14b", size = 10011941, upload-time = "2026-08-27T16:33:41.287Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/4b/46/6cf67cf6411885a1d6f7f6d801682f155536a85176d10b605e2ceffed8bd/ruff-0.16.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eda58a5802de40e7ed5b32b64e0b32539338cc6fcd2c78f61e3ad6a0d79f51c3", size = 10204049, upload-time = "2026-08-27T16:33:44.056Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/fd/c8720ca7a090abf0c2fef4abe8a5ef6e5127ed15196d8886ff75a2b370e2/ruff-0.16.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5ae9a7b9a8875131f40f8fe967cc86abf899779efd663cb7ce3d572d01da7eb", size = 9809037, upload-time = "2026-08-27T16:33:46.257Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/45/a684caacdedaca180f52bacccc40bf0789d2c5a7c75f25324853e9eaedb5/ruff-0.16.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b719b0a1f4d59710d283ab2965f621684a108a9e41da622e3b23f0326cd0025", size = 9964129, upload-time = "2026-08-27T16:33:48.352Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/5d2bcdaca6b5b93d1b4dfc166cd2aebf7680143a1b38a28759df13a94d31/ruff-0.16.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2298f2780ed1be0c5cb1361e32ab7b1467f3cce7dabe101d2210a314f2fe42e9", size = 9821518, upload-time = "2026-08-27T16:33:50.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/ff/011cce29accf9257d5974145b733fc653a37985ed6825413a3987cefbfe0/ruff-0.16.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:258f29035a2dd021e7861e631b227a5b3f14e50c1184c9a6a122c5f4576154d7", size = 10534835, upload-time = "2026-08-27T16:33:52.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/5a/f0cf109bada9bba0e96c90c21c9f9251803f57225c32d293327a03c710d6/ruff-0.16.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9a4f0432966834019c74d1b7e5c51224305d7713f3d7faf3e7451f1a3be3cde", size = 11252550, upload-time = "2026-08-27T16:33:54.521Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
|
{ url = "https://files.pythonhosted.org/packages/63/4d/1d481aaea2046c6a7ed7c291f9004c669cce3c087b6b376ed5b08271e3fe/ruff-0.16.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5eb3a8c3d0ade9cea42b591fd530368e8798380e30e0a308b85a5cf718f09ea", size = 10777949, upload-time = "2026-08-27T16:33:56.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/34/ee245ca55f64443233034b3d02b03236b19242004281247c079390b7facd/ruff-0.16.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0f69e191a13a3c9816f63163c88790cb12cd157bbbb384e9c44745702ab105", size = 10311656, upload-time = "2026-08-27T16:33:59.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/c33a333e341c0a2b96c715b52d89a606f5a34cd4ac493cd9b8d0187186b8/ruff-0.16.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0eeab41fbea2c42f98dfb9822cdccda9d24ba38d49f6dc945b5c236d48f0ef29", size = 10532125, upload-time = "2026-08-27T16:34:01.166Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/e1/a64cef78b40192497bb98a27a8aa8f2c98ee9ee15bc97f7712d94ef32937/ruff-0.16.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0768e9df4300713fff30733c87575f68b6f1d8de41184e505b7fdd9c0c95eaf", size = 10097648, upload-time = "2026-08-27T16:34:03.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/4e/4cdc9ed3c3e109d2f71e62572a37457298d7bc7501ec3138babb7ed32bbd/ruff-0.16.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:95cc70cdc7aa80c338de356279d2adbeb2de0f520b9ecd8aba75b94e95e02f91", size = 9829344, upload-time = "2026-08-27T16:34:05.134Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/4a/31ed35ce31729955fc583ee0d176d6e784c1290cb0b0a75cb2134c1ab72a/ruff-0.16.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d185c8398ded1bfd91c0c2cb258346307571eccc473a8490af8c3977399c384a", size = 10277117, upload-time = "2026-08-27T16:34:07.425Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a0/60356d86687b4b666d593df213f4dc3041750d024cb7bf2cfa81cfd65c2e/ruff-0.16.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fb8e3a3c4c6a784150a7ced53b015f4b253fc2bf97a610886419ead64b4756ef", size = 10711653, upload-time = "2026-08-27T16:34:09.712Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/20/656d67f5b25ca9bda4e02b1de25867b2954e1d19e03648060f167ad0f4cc/ruff-0.16.5-py3-none-win32.whl", hash = "sha256:288b0a5f080492fe5635db849f9e2e84aa3cce7b7f0e955997d416c507c76a26", size = 10034250, upload-time = "2026-08-27T16:34:11.8Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/42/ee8e68a207b9127fcde6c3d7e197def432f346cb1af159e1fa14ca0d1cdc/ruff-0.16.5-py3-none-win_amd64.whl", hash = "sha256:ddc6385fb2137f616357ca03d6c74f4be987f80fed4008566b754f6032b8546f", size = 10516714, upload-time = "2026-08-27T16:34:13.963Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
|
{ url = "https://files.pythonhosted.org/packages/73/e3/7df5a396e445b9ba49ce9a9437439a4d80042c61c0ade199abf8d16de1ac/ruff-0.16.5-py3-none-win_arm64.whl", hash = "sha256:a64abe90968719b851bb7cedffaa8753fbdbdadab483089682db623f3edc587e", size = 10391564, upload-time = "2026-08-27T16:34:16.064Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1045,27 +1067,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.55"
|
version = "0.0.75"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/48/f687c8d268e3581f2f104d1f2ac5944d5b5e841b3695c613b3f263e5bbf7/ty-0.0.55.tar.gz", hash = "sha256:88ca87073825a79a8327c550efcc86cec94344890244c5946f84c9e44a969f31", size = 6040230, upload-time = "2026-06-27T00:27:29.385Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/81/d0/d0c96f898d6974a4a3569ab3efdf9512c04ad99f9203effb55f72497fe97/ty-0.0.75.tar.gz", hash = "sha256:4c5eead33dfbf6e2ebb4f400f74b51ffc9bab702a6f23ddb648a1cbb740387e3", size = 6868326, upload-time = "2026-08-26T20:23:40.399Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/a3/1a90ba7e5a61c6d09adb92346ddba97668095fc257b577af433e5ac4f404/ty-0.0.55-py3-none-linux_armv6l.whl", hash = "sha256:31e83eef512d066542fe990fe1a3b814423abd1616376c54e48af7045b3e1749", size = 11677249, upload-time = "2026-06-27T00:26:52.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/6c/b12d03505f17581f0cfa3c12273fe34c1d67b36dfda1bc561a6bdc16512b/ty-0.0.75-py3-none-linux_armv6l.whl", hash = "sha256:e5409f50db2246fd4bd039d93d261e0cfa1daa554a4fb77256f91072c570349a", size = 12972606, upload-time = "2026-08-26T20:22:59.716Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/3a/669f9aa478c38243e213a2684db1502086026cfadc15bb1b29b7cbde030d/ty-0.0.55-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab4bca857950608fea73e269e2da369d43e6467131de85160d68e2fa466fa248", size = 11444180, upload-time = "2026-06-27T00:26:54.576Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/aa/30f11eecd9215a9f87e8fe8baaf48f3ce905f5d75b8e4aac70f0091f130c/ty-0.0.75-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5e7b8b3472fb9bb2eeab314984b265df08a7a9d518867a9e6020eebc06570be2", size = 12527158, upload-time = "2026-08-26T20:23:02.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/a4/6a4b2507a53ce6530c66c5b4fe0d58551eb1748ffa9e0696c32fdd55bbd4/ty-0.0.55-py3-none-macosx_11_0_arm64.whl", hash = "sha256:55032bfd31bf2c5355ee81bdc6407b144a1cc7ee41e5681dd1368e4cef2ba327", size = 10963134, upload-time = "2026-06-27T00:26:57.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/f2/11/7fd7001b0b5c6610bfbad7357e47d5fe6f82d4e84e94c53776a478f5e9f8/ty-0.0.75-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c6ccf34169821fe0d23e3360deeef981d217963412f1d087b9bdd32ec57f7a57", size = 12400533, upload-time = "2026-08-26T20:23:04.965Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/ae/a3b1a0f1cc83b7d258662cb98aa80a720c2e671d0e8fa0d17a4d5d057a7a/ty-0.0.55-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1e049f69ce65b3c269af67624607f435e1c32319786c1e453ef9611502f295", size = 11493517, upload-time = "2026-06-27T00:26:59.26Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/7f/1e284ea3d348d7be02f12d83bc22ed9ef193033f863f05b64db99027f141/ty-0.0.75-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842ebb41e9c6c334b40768704e20b1a69d5c6b08805b289d5e0e2565f49f2de1", size = 12420592, upload-time = "2026-08-26T20:23:07.427Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/9f/311ce39065a979ef40a9b847f685c8e02464e53adf1671e081eea90640ca/ty-0.0.55-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:631409975c681d5a280fc5a99b7b32e9e801f33be7567c6b42ec331362f59d7d", size = 11460590, upload-time = "2026-06-27T00:27:01.425Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/ab/d813271543370c47fd74b5118f2066ab32b0983e907b1821f3f9a6d0fa7f/ty-0.0.75-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7a5a723c5f1e0fab4ffbfe9bd95123a526ed48f206e5f25cb2161ca294007a", size = 12739219, upload-time = "2026-08-26T20:23:09.809Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/8f/3bf29aa77bd78aae48275153135a2052fa7d3ccdf1ecabeb99c8773abd66/ty-0.0.55-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e08cb0436e68b9351555ae8f2697138c9009b4d5b4ae4272232988b2a431a98f", size = 12098430, upload-time = "2026-06-27T00:27:03.596Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/5b/95b49cc5570fd92a7bf63732f649b31906158721e03c7fcb1b5be74ee3bf/ty-0.0.75-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54382f98e5da292fcd7104391afef5105c35bb2f312e29bea6f5fa419935255c", size = 13494046, upload-time = "2026-08-26T20:23:12.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6e/e88411a88240b94640bba06fb6d0d92b247fbeef47ee2bc71f39e58c2558/ty-0.0.55-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16c215ad9f823829409b94ee188cfaa4563f6e1384f6ce3fecb1db75f6c7cf7c", size = 12673086, upload-time = "2026-06-27T00:27:05.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/0d/502d2dd68173cf020e1ad2bdbab9544c86776de0b0e2ed15f8c2fe006e3d/ty-0.0.75-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac13b180dc2aade2cd243f56b01650e78bf091a2e522ad3bc947245d7837c613", size = 13938899, upload-time = "2026-08-26T20:23:14.764Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/7e/8f1762fb7f9245a68ba5ae338d73c59403ce57554e5d311b8bb55027b0ec/ty-0.0.55-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b510eb8f4032baf11b7aee2f1d53babc3b4ca03939b9cdcf6a9d15761d575188", size = 12242559, upload-time = "2026-06-27T00:27:07.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/5b/f3b12a25c07224456219fc2bd20db0ad7e40b304be0ff6aad728da0135f9/ty-0.0.75-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:752df7951a443219d7f1ff817e3723c85d428565ff449e08a7a93ba821661526", size = 13656711, upload-time = "2026-08-26T20:23:17.145Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/1f/143657daf2670d977dac83435f1fe03d4843efb798d8e1e75950e541aadd/ty-0.0.55-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc05e7959709c3b9b83aa627128a80446865e3c1a4882638dcff6d776dc34a", size = 12021409, upload-time = "2026-06-27T00:27:09.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/7b/f090ad306e2b15a07b332d647138c5264b89d9758855ecce8b8a10bcb153/ty-0.0.75-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd399feedf7cee816563c1baec45fc1c0b3c89f1ea42364920b688004b5b7da", size = 13093499, upload-time = "2026-08-26T20:23:19.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/30/69487c439dd1fad3a4a3d96f0a472193de297eaba6fc4b8ea687ce434ac2/ty-0.0.55-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:636e8e5078787b8c6916c94e1406719f10189a4ca6b37b813a5922ce5857a8c7", size = 12303807, upload-time = "2026-06-27T00:27:11.986Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/4b/f69b99aaaca0c7c65d5f114b186b26b21666f767b0c69eec99a2bdccc061/ty-0.0.75-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d7625f6f56c7dc1e873579fdc9e432a0e21e302afe847ab60704d2303442a92e", size = 13520580, upload-time = "2026-08-26T20:23:21.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/ca/cd88b6493dafc7db077f5e17c0438eb3af6e2d6d08f616dbb52a8ddfd567/ty-0.0.55-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ef7d6deaacb73fec603666b5471f1dc5a5699aa84e11a6d4d644dd07ca72121e", size = 11441263, upload-time = "2026-06-27T00:27:14.087Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/e7/692c5f905c0345a15d2255fc74066d660f030254ae8dcdaf33f5a5c2f279/ty-0.0.75-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:89e7d527e95a2534b70cae29e94c104b84082760ea05927d23bb87280969c104", size = 12524095, upload-time = "2026-08-26T20:23:24.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/fe/66b6915671653ab739f71e4f1b0528e69da64429b7ebf3840c625b6e43f2/ty-0.0.55-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9aeea0fe5875d3cf37faf0e44d0fdf9669335467749741b8fc0103916fb5cd32", size = 11484584, upload-time = "2026-06-27T00:27:16.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/9a/f42b12cf265ea95344bf554764c4791cfb273bdd628aadd7c209af7cadc3/ty-0.0.75-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0843f134440740706e01bee5f88f4cfc10e9b018bddb9e4ef4c12dc9fc0c9aef", size = 12756591, upload-time = "2026-08-26T20:23:26.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/4f/7a9c0bbac8b899e9f6c0ec110c6612f52e4db35f6bb17ddc0ef60384fa3e/ty-0.0.55-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b699c01310dbd2705a07c97c5f4aaeedef61bd9adeea2e7c46aed32401d3576", size = 11759309, upload-time = "2026-06-27T00:27:18.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/5e/9b180c133cb9cce48179a7d2bf9e1802d992aa8176a918e0e05205760b42/ty-0.0.75-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1bd0ec0e50ee1376875c88891efe6f549c3560fa5b2ddad79a425cd5a6218b9c", size = 12998754, upload-time = "2026-08-26T20:23:28.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/de/b6f8b1b69aa631b5716ef3f985c3b56de0e46c2499cc00d30c402b41f714/ty-0.0.55-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32cbeba543e46de2a983ec6d525d8b56514f7422bd1e1b57c44ccf7bfa72c38a", size = 12128755, upload-time = "2026-06-27T00:27:20.55Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/f6/3c6ef5dd550103e29905121c67fb96a374564f31a2f44c6faa1af98c2d61/ty-0.0.75-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f9eafd561f90110d5e29f589ec3e956c4686e2f6631348d99276436f5cbe4d1", size = 13316474, upload-time = "2026-08-26T20:23:30.857Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/90/a912531e51ee7e076b42972479290fa687c0f5e747b7e773f3033164acaa/ty-0.0.55-py3-none-win32.whl", hash = "sha256:52b968e24eb4f7a5c3bd251db1f99f60dd385890356d38fc619d84f1b423446a", size = 11117501, upload-time = "2026-06-27T00:27:22.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/52/12776337874c821076bd5368e352ccd9e67174790abe3b856f749cb3524b/ty-0.0.75-py3-none-win32.whl", hash = "sha256:05063a6fafe2154b794a7f964515d148e51acd186d72d4a3acd347ee9fa19336", size = 12316315, upload-time = "2026-08-26T20:23:33.528Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/7a/99d59843bf8908a7f9f4d13fda107dbad07b7faa28ecd7860eacf363fb1c/ty-0.0.55-py3-none-win_amd64.whl", hash = "sha256:bf39cbfdc0add44d94bd3fff1f53c351418d134b6a66b87efdb7876d7b7a2224", size = 12150106, upload-time = "2026-06-27T00:27:24.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/e6/bb51e16af5c7138c9f52f8f3d0a401a371c6798d092e3b74926f186a9814/ty-0.0.75-py3-none-win_amd64.whl", hash = "sha256:81cf1ba5f6b7536ad56747865214255d9bc8e80533a689dbb9ddeaad464b09f1", size = 12917267, upload-time = "2026-08-26T20:23:35.978Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/44/20987505cedf2a865b08482f0eabc181fd9599b062964057ec8a128a4296/ty-0.0.55-py3-none-win_arm64.whl", hash = "sha256:f7f3700a9a060e8f1af11e4fb63fafcaf272b041781f4ccdfda2b3b5c6c1e439", size = 11560157, upload-time = "2026-06-27T00:27:27.332Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/73/4542f829107468b5de4231af67f29927c093bfad11f3c1e5b2c08fb1206b/ty-0.0.75-py3-none-win_arm64.whl", hash = "sha256:541c9af5b7a0ad23d15ec315a7da81150833c359f48124ed3789ff25eacd6f42", size = 12711024, upload-time = "2026-08-26T20:23:38.159Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ class SqliteSaver(BaseCheckpointSaver[str]):
|
|||||||
>>> result = graph.invoke(3, config)
|
>>> result = graph.invoke(3, config)
|
||||||
>>> graph.get_state(config)
|
>>> graph.get_state(config)
|
||||||
StateSnapshot(values=4, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '0c62ca34-ac19-445d-bbb0-5b4984975b2a'}}, parent_config=None)
|
StateSnapshot(values=4, next=(), config={'configurable': {'thread_id': '1', 'checkpoint_ns': '', 'checkpoint_id': '0c62ca34-ac19-445d-bbb0-5b4984975b2a'}}, parent_config=None)
|
||||||
""" # noqa
|
"""
|
||||||
|
|
||||||
conn: sqlite3.Connection
|
conn: sqlite3.Connection
|
||||||
is_setup: bool
|
is_setup: bool
|
||||||
@@ -222,7 +222,7 @@ class SqliteSaver(BaseCheckpointSaver[str]):
|
|||||||
>>> checkpoint_tuple = memory.get_tuple(config)
|
>>> checkpoint_tuple = memory.get_tuple(config)
|
||||||
>>> print(checkpoint_tuple)
|
>>> print(checkpoint_tuple)
|
||||||
CheckpointTuple(...)
|
CheckpointTuple(...)
|
||||||
""" # noqa
|
"""
|
||||||
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
||||||
with self.cursor(transaction=False) as cur:
|
with self.cursor(transaction=False) as cur:
|
||||||
# find the latest checkpoint for the thread_id
|
# find the latest checkpoint for the thread_id
|
||||||
|
|||||||
@@ -212,7 +212,7 @@ class AsyncSqliteSaver(BaseCheckpointSaver[str]):
|
|||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
yield asyncio.run_coroutine_threadsafe(
|
yield asyncio.run_coroutine_threadsafe(
|
||||||
anext(aiter_), # type: ignore[arg-type] # noqa: F821
|
anext(aiter_), # type: ignore[arg-type]
|
||||||
self.loop,
|
self.loop,
|
||||||
).result()
|
).result()
|
||||||
except StopAsyncIteration:
|
except StopAsyncIteration:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import re
|
|||||||
import sqlite3
|
import sqlite3
|
||||||
import threading
|
import threading
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Callable, Iterable, Iterator, Sequence
|
from collections.abc import Callable, Iterable, Iterator, Mapping, Sequence
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Any, Literal, NamedTuple, cast
|
from typing import Any, Literal, NamedTuple, cast
|
||||||
|
|
||||||
@@ -387,7 +387,7 @@ class BaseSqliteStore:
|
|||||||
[
|
[
|
||||||
_namespace_to_text(op.namespace),
|
_namespace_to_text(op.namespace),
|
||||||
op.key,
|
op.key,
|
||||||
orjson.dumps(cast(dict, op.value)),
|
orjson.dumps(dict(cast(Mapping[str, Any], op.value))),
|
||||||
expires_at,
|
expires_at,
|
||||||
op.ttl,
|
op.ttl,
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ test = [
|
|||||||
"pytest-mock",
|
"pytest-mock",
|
||||||
"pytest-watcher",
|
"pytest-watcher",
|
||||||
"langgraph-checkpoint",
|
"langgraph-checkpoint",
|
||||||
|
"langgraph-checkpoint-conformance",
|
||||||
"pytest-retry>=1.7.0",
|
"pytest-retry>=1.7.0",
|
||||||
]
|
]
|
||||||
lint = [
|
lint = [
|
||||||
@@ -47,6 +48,7 @@ default-groups = ['dev']
|
|||||||
|
|
||||||
[tool.uv.sources]
|
[tool.uv.sources]
|
||||||
langgraph-checkpoint = { path = "../checkpoint", editable = true }
|
langgraph-checkpoint = { path = "../checkpoint", editable = true }
|
||||||
|
langgraph-checkpoint-conformance = { path = "../checkpoint-conformance", editable = true }
|
||||||
|
|
||||||
[tool.hatch.build.targets.wheel]
|
[tool.hatch.build.targets.wheel]
|
||||||
include = ["langgraph"]
|
include = ["langgraph"]
|
||||||
@@ -62,6 +64,8 @@ lint.select = [
|
|||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
|
"PLC0415", # import-outside-top-level
|
||||||
|
"RUF100", # unused noqa directive
|
||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
]
|
]
|
||||||
lint.ignore = ["E501", "B008"]
|
lint.ignore = ["E501", "B008"]
|
||||||
|
|||||||
@@ -3,21 +3,14 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
|
from langgraph.checkpoint.conformance import validate
|
||||||
|
from langgraph.checkpoint.conformance.initializer import checkpointer_test
|
||||||
|
|
||||||
pytest.importorskip(
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
||||||
"langgraph.checkpoint.conformance",
|
|
||||||
reason="langgraph-checkpoint-conformance not installed",
|
|
||||||
)
|
|
||||||
pytest.importorskip("aiosqlite", reason="aiosqlite not installed")
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_delta_channel_conformance():
|
async def test_delta_channel_conformance():
|
||||||
from langgraph.checkpoint.conformance import validate
|
|
||||||
from langgraph.checkpoint.conformance.initializer import checkpointer_test
|
|
||||||
|
|
||||||
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
|
||||||
|
|
||||||
@checkpointer_test(name="AsyncSqliteSaver")
|
@checkpointer_test(name="AsyncSqliteSaver")
|
||||||
async def sqlite_saver():
|
async def sqlite_saver():
|
||||||
async with AsyncSqliteSaver.from_conn_string(":memory:") as saver:
|
async with AsyncSqliteSaver.from_conn_string(":memory:") as saver:
|
||||||
|
|||||||
@@ -29,13 +29,13 @@ pytest.importorskip("langgraph.channels.delta", reason="langgraph core not insta
|
|||||||
pytest.importorskip("langgraph.channels.binop", reason="langgraph core not installed")
|
pytest.importorskip("langgraph.channels.binop", reason="langgraph core not installed")
|
||||||
pytest.importorskip("langgraph.graph", reason="langgraph core not installed")
|
pytest.importorskip("langgraph.graph", reason="langgraph core not installed")
|
||||||
|
|
||||||
from langgraph.channels.binop import BinaryOperatorAggregate # type: ignore[import-untyped] # noqa: E402,I001
|
from langgraph.channels.binop import BinaryOperatorAggregate # type: ignore[import-untyped] # noqa: I001
|
||||||
from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: E402
|
from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped]
|
||||||
from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] # noqa: E402
|
from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped]
|
||||||
from typing_extensions import TypedDict # noqa: E402
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
from langgraph.checkpoint.sqlite import SqliteSaver # noqa: E402
|
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||||
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver # noqa: E402
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
||||||
|
|
||||||
pytestmark = pytest.mark.anyio
|
pytestmark = pytest.mark.anyio
|
||||||
|
|
||||||
|
|||||||
@@ -32,13 +32,13 @@ from langchain_core.runnables import RunnableConfig
|
|||||||
pytest.importorskip("langgraph.channels.delta", reason="langgraph core not installed")
|
pytest.importorskip("langgraph.channels.delta", reason="langgraph core not installed")
|
||||||
pytest.importorskip("langgraph.graph", reason="langgraph core not installed")
|
pytest.importorskip("langgraph.graph", reason="langgraph core not installed")
|
||||||
|
|
||||||
from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: E402,I001
|
from langgraph.channels.delta import DeltaChannel # type: ignore[import-untyped] # noqa: I001
|
||||||
from langgraph.checkpoint.serde.types import _DeltaSnapshot # noqa: E402
|
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
||||||
from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped] # noqa: E402
|
from langgraph.graph import END, START, StateGraph # type: ignore[import-untyped]
|
||||||
from typing_extensions import TypedDict # noqa: E402
|
from typing_extensions import TypedDict
|
||||||
|
|
||||||
from langgraph.checkpoint.sqlite import SqliteSaver # noqa: E402
|
from langgraph.checkpoint.sqlite import SqliteSaver
|
||||||
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver # noqa: E402
|
from langgraph.checkpoint.sqlite.aio import AsyncSqliteSaver
|
||||||
|
|
||||||
pytestmark = pytest.mark.anyio
|
pytestmark = pytest.mark.anyio
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
|
import math
|
||||||
import os
|
import os
|
||||||
|
import random
|
||||||
import re
|
import re
|
||||||
import tempfile
|
import tempfile
|
||||||
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
from collections import Counter, defaultdict
|
||||||
from collections.abc import Generator, Iterable
|
from collections.abc import Generator, Iterable
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import Any, Literal, cast
|
from typing import Any, Literal, cast
|
||||||
@@ -33,10 +37,6 @@ class CharacterEmbeddings(Embeddings):
|
|||||||
|
|
||||||
def __init__(self, dims: int = 50, seed: int = 42):
|
def __init__(self, dims: int = 50, seed: int = 42):
|
||||||
"""Initialize with embedding dimensions and random seed."""
|
"""Initialize with embedding dimensions and random seed."""
|
||||||
import math
|
|
||||||
import random
|
|
||||||
from collections import defaultdict
|
|
||||||
|
|
||||||
self._rng = random.Random(seed)
|
self._rng = random.Random(seed)
|
||||||
self.dims = dims
|
self.dims = dims
|
||||||
# Create projection vector for each character lazily
|
# Create projection vector for each character lazily
|
||||||
@@ -48,9 +48,6 @@ class CharacterEmbeddings(Embeddings):
|
|||||||
|
|
||||||
def _embed_one(self, text: str) -> list[float]:
|
def _embed_one(self, text: str) -> list[float]:
|
||||||
"""Embed a single text."""
|
"""Embed a single text."""
|
||||||
import math
|
|
||||||
from collections import Counter
|
|
||||||
|
|
||||||
counts = Counter(text)
|
counts = Counter(text)
|
||||||
total = sum(counts.values())
|
total = sum(counts.values())
|
||||||
|
|
||||||
@@ -338,8 +335,6 @@ class TestSqliteStore:
|
|||||||
|
|
||||||
# Test update
|
# Test update
|
||||||
# Small delay to ensure the updated timestamp is different
|
# Small delay to ensure the updated timestamp is different
|
||||||
import time
|
|
||||||
|
|
||||||
time.sleep(0.01)
|
time.sleep(0.01)
|
||||||
|
|
||||||
updated_value = {"title": "Updated Document", "content": "Hello, Updated!"}
|
updated_value = {"title": "Updated Document", "content": "Hello, Updated!"}
|
||||||
|
|||||||
Generated
+80
-49
@@ -26,16 +26,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.12.1"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ 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 = [
|
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]]
|
[[package]]
|
||||||
@@ -147,11 +147,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespell"
|
name = "codespell"
|
||||||
version = "2.4.2"
|
version = "2.4.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/80/19/45e941380f69c042b43423513d201e6592346f992394347f5e7174c31407/codespell-2.4.3.tar.gz", hash = "sha256:cbe085e331227b37bb86ef8bddd08dc768c704ee9a07ca869852c093fa2793e2", size = 352773, upload-time = "2026-07-15T11:51:54.159Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
|
{ url = "https://files.pythonhosted.org/packages/8b/bf/bdb951d34eb169140b546f44be9ec4525d1acefb9eb5572071f5492b19fc/codespell-2.4.3-py3-none-any.whl", hash = "sha256:af2505b335e8573dbd2d384d1c4ef498f4006f4ba2d6fceca01e55b91f52628a", size = 340736, upload-time = "2026-07-15T11:51:52.925Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -168,7 +168,7 @@ name = "exceptiongroup"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ 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" }
|
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 = [
|
wheels = [
|
||||||
@@ -253,7 +253,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.4.8"
|
version = "1.5.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
@@ -266,9 +266,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/12/e3/bea6d0080acf183332f24dcd74c208aee5857cf8f783c3fb0bd86027d8fb/langchain_core-1.4.8.tar.gz", hash = "sha256:5bf1f8411077c904182ad8f975943d36adcbf579c4e017b3a118b719229ebf9a", size = 957974, upload-time = "2026-06-18T19:39:23.636Z" }
|
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" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl", hash = "sha256:d84c28b05e3ba8d4271d0827aad5b592ccdaaf986e76768c23503f0a2045e8aa", size = 557416, upload-time = "2026-06-18T19:39:21.902Z" },
|
{ 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" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -285,7 +285,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.1.1"
|
version = "4.2.0"
|
||||||
source = { editable = "../checkpoint" }
|
source = { editable = "../checkpoint" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -331,6 +331,33 @@ test = [
|
|||||||
{ name = "redis" },
|
{ name = "redis" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "langgraph-checkpoint-conformance"
|
||||||
|
version = "0.0.2"
|
||||||
|
source = { editable = "../checkpoint-conformance" }
|
||||||
|
dependencies = [
|
||||||
|
{ name = "langgraph-checkpoint" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[package.metadata]
|
||||||
|
requires-dist = [{ name = "langgraph-checkpoint", editable = "../checkpoint" }]
|
||||||
|
|
||||||
|
[package.metadata.requires-dev]
|
||||||
|
dev = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "pytest-asyncio" },
|
||||||
|
{ name = "ruff" },
|
||||||
|
{ name = "ty" },
|
||||||
|
]
|
||||||
|
lint = [
|
||||||
|
{ name = "ruff" },
|
||||||
|
{ name = "ty" },
|
||||||
|
]
|
||||||
|
test = [
|
||||||
|
{ name = "pytest" },
|
||||||
|
{ name = "pytest-asyncio" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint-sqlite"
|
name = "langgraph-checkpoint-sqlite"
|
||||||
version = "3.1.1"
|
version = "3.1.1"
|
||||||
@@ -345,6 +372,7 @@ dependencies = [
|
|||||||
dev = [
|
dev = [
|
||||||
{ name = "codespell" },
|
{ name = "codespell" },
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
{ name = "pytest-mock" },
|
{ name = "pytest-mock" },
|
||||||
@@ -360,6 +388,7 @@ lint = [
|
|||||||
]
|
]
|
||||||
test = [
|
test = [
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
{ name = "pytest-mock" },
|
{ name = "pytest-mock" },
|
||||||
@@ -378,6 +407,7 @@ requires-dist = [
|
|||||||
dev = [
|
dev = [
|
||||||
{ name = "codespell" },
|
{ name = "codespell" },
|
||||||
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance", editable = "../checkpoint-conformance" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
{ name = "pytest-mock" },
|
{ name = "pytest-mock" },
|
||||||
@@ -393,6 +423,7 @@ lint = [
|
|||||||
]
|
]
|
||||||
test = [
|
test = [
|
||||||
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
{ name = "langgraph-checkpoint", editable = "../checkpoint" },
|
||||||
|
{ name = "langgraph-checkpoint-conformance", editable = "../checkpoint-conformance" },
|
||||||
{ name = "pytest" },
|
{ name = "pytest" },
|
||||||
{ name = "pytest-asyncio" },
|
{ name = "pytest-asyncio" },
|
||||||
{ name = "pytest-mock" },
|
{ name = "pytest-mock" },
|
||||||
@@ -880,27 +911,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.20"
|
version = "0.16.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/85/c8e12473c93018f92d19dd988a294202e1c27426c47ec4de53ffb847b8d8/ruff-0.16.5.tar.gz", hash = "sha256:1b88500f9ffbcab3dedb0082c9f9492e91ec3d618aac1236a3e0189938f7040b", size = 4912003, upload-time = "2026-08-27T16:34:18.258Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/b6/77c90a970fe2dae17a723acbd011043ea97c98d7deacccefdc4ba74ec512/ruff-0.16.5-py3-none-linux_armv6l.whl", hash = "sha256:12e5f673e774c35fbb62f288809c7653b73445f8ecec6b6063fd6ea3521aa14b", size = 10011941, upload-time = "2026-08-27T16:33:41.287Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/4b/46/6cf67cf6411885a1d6f7f6d801682f155536a85176d10b605e2ceffed8bd/ruff-0.16.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eda58a5802de40e7ed5b32b64e0b32539338cc6fcd2c78f61e3ad6a0d79f51c3", size = 10204049, upload-time = "2026-08-27T16:33:44.056Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/fd/c8720ca7a090abf0c2fef4abe8a5ef6e5127ed15196d8886ff75a2b370e2/ruff-0.16.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5ae9a7b9a8875131f40f8fe967cc86abf899779efd663cb7ce3d572d01da7eb", size = 9809037, upload-time = "2026-08-27T16:33:46.257Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/45/a684caacdedaca180f52bacccc40bf0789d2c5a7c75f25324853e9eaedb5/ruff-0.16.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b719b0a1f4d59710d283ab2965f621684a108a9e41da622e3b23f0326cd0025", size = 9964129, upload-time = "2026-08-27T16:33:48.352Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/5d2bcdaca6b5b93d1b4dfc166cd2aebf7680143a1b38a28759df13a94d31/ruff-0.16.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2298f2780ed1be0c5cb1361e32ab7b1467f3cce7dabe101d2210a314f2fe42e9", size = 9821518, upload-time = "2026-08-27T16:33:50.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/ff/011cce29accf9257d5974145b733fc653a37985ed6825413a3987cefbfe0/ruff-0.16.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:258f29035a2dd021e7861e631b227a5b3f14e50c1184c9a6a122c5f4576154d7", size = 10534835, upload-time = "2026-08-27T16:33:52.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/5a/f0cf109bada9bba0e96c90c21c9f9251803f57225c32d293327a03c710d6/ruff-0.16.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9a4f0432966834019c74d1b7e5c51224305d7713f3d7faf3e7451f1a3be3cde", size = 11252550, upload-time = "2026-08-27T16:33:54.521Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
|
{ url = "https://files.pythonhosted.org/packages/63/4d/1d481aaea2046c6a7ed7c291f9004c669cce3c087b6b376ed5b08271e3fe/ruff-0.16.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5eb3a8c3d0ade9cea42b591fd530368e8798380e30e0a308b85a5cf718f09ea", size = 10777949, upload-time = "2026-08-27T16:33:56.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/34/ee245ca55f64443233034b3d02b03236b19242004281247c079390b7facd/ruff-0.16.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0f69e191a13a3c9816f63163c88790cb12cd157bbbb384e9c44745702ab105", size = 10311656, upload-time = "2026-08-27T16:33:59.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/c33a333e341c0a2b96c715b52d89a606f5a34cd4ac493cd9b8d0187186b8/ruff-0.16.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0eeab41fbea2c42f98dfb9822cdccda9d24ba38d49f6dc945b5c236d48f0ef29", size = 10532125, upload-time = "2026-08-27T16:34:01.166Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/e1/a64cef78b40192497bb98a27a8aa8f2c98ee9ee15bc97f7712d94ef32937/ruff-0.16.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0768e9df4300713fff30733c87575f68b6f1d8de41184e505b7fdd9c0c95eaf", size = 10097648, upload-time = "2026-08-27T16:34:03.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/4e/4cdc9ed3c3e109d2f71e62572a37457298d7bc7501ec3138babb7ed32bbd/ruff-0.16.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:95cc70cdc7aa80c338de356279d2adbeb2de0f520b9ecd8aba75b94e95e02f91", size = 9829344, upload-time = "2026-08-27T16:34:05.134Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/4a/31ed35ce31729955fc583ee0d176d6e784c1290cb0b0a75cb2134c1ab72a/ruff-0.16.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d185c8398ded1bfd91c0c2cb258346307571eccc473a8490af8c3977399c384a", size = 10277117, upload-time = "2026-08-27T16:34:07.425Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a0/60356d86687b4b666d593df213f4dc3041750d024cb7bf2cfa81cfd65c2e/ruff-0.16.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fb8e3a3c4c6a784150a7ced53b015f4b253fc2bf97a610886419ead64b4756ef", size = 10711653, upload-time = "2026-08-27T16:34:09.712Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/20/656d67f5b25ca9bda4e02b1de25867b2954e1d19e03648060f167ad0f4cc/ruff-0.16.5-py3-none-win32.whl", hash = "sha256:288b0a5f080492fe5635db849f9e2e84aa3cce7b7f0e955997d416c507c76a26", size = 10034250, upload-time = "2026-08-27T16:34:11.8Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/42/ee8e68a207b9127fcde6c3d7e197def432f346cb1af159e1fa14ca0d1cdc/ruff-0.16.5-py3-none-win_amd64.whl", hash = "sha256:ddc6385fb2137f616357ca03d6c74f4be987f80fed4008566b754f6032b8546f", size = 10516714, upload-time = "2026-08-27T16:34:13.963Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
|
{ url = "https://files.pythonhosted.org/packages/73/e3/7df5a396e445b9ba49ce9a9437439a4d80042c61c0ade199abf8d16de1ac/ruff-0.16.5-py3-none-win_arm64.whl", hash = "sha256:a64abe90968719b851bb7cedffaa8753fbdbdadab483089682db623f3edc587e", size = 10391564, upload-time = "2026-08-27T16:34:16.064Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -980,27 +1011,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.55"
|
version = "0.0.75"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/48/f687c8d268e3581f2f104d1f2ac5944d5b5e841b3695c613b3f263e5bbf7/ty-0.0.55.tar.gz", hash = "sha256:88ca87073825a79a8327c550efcc86cec94344890244c5946f84c9e44a969f31", size = 6040230, upload-time = "2026-06-27T00:27:29.385Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/81/d0/d0c96f898d6974a4a3569ab3efdf9512c04ad99f9203effb55f72497fe97/ty-0.0.75.tar.gz", hash = "sha256:4c5eead33dfbf6e2ebb4f400f74b51ffc9bab702a6f23ddb648a1cbb740387e3", size = 6868326, upload-time = "2026-08-26T20:23:40.399Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/a3/1a90ba7e5a61c6d09adb92346ddba97668095fc257b577af433e5ac4f404/ty-0.0.55-py3-none-linux_armv6l.whl", hash = "sha256:31e83eef512d066542fe990fe1a3b814423abd1616376c54e48af7045b3e1749", size = 11677249, upload-time = "2026-06-27T00:26:52.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/6c/b12d03505f17581f0cfa3c12273fe34c1d67b36dfda1bc561a6bdc16512b/ty-0.0.75-py3-none-linux_armv6l.whl", hash = "sha256:e5409f50db2246fd4bd039d93d261e0cfa1daa554a4fb77256f91072c570349a", size = 12972606, upload-time = "2026-08-26T20:22:59.716Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/3a/669f9aa478c38243e213a2684db1502086026cfadc15bb1b29b7cbde030d/ty-0.0.55-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab4bca857950608fea73e269e2da369d43e6467131de85160d68e2fa466fa248", size = 11444180, upload-time = "2026-06-27T00:26:54.576Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/aa/30f11eecd9215a9f87e8fe8baaf48f3ce905f5d75b8e4aac70f0091f130c/ty-0.0.75-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5e7b8b3472fb9bb2eeab314984b265df08a7a9d518867a9e6020eebc06570be2", size = 12527158, upload-time = "2026-08-26T20:23:02.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/a4/6a4b2507a53ce6530c66c5b4fe0d58551eb1748ffa9e0696c32fdd55bbd4/ty-0.0.55-py3-none-macosx_11_0_arm64.whl", hash = "sha256:55032bfd31bf2c5355ee81bdc6407b144a1cc7ee41e5681dd1368e4cef2ba327", size = 10963134, upload-time = "2026-06-27T00:26:57.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/f2/11/7fd7001b0b5c6610bfbad7357e47d5fe6f82d4e84e94c53776a478f5e9f8/ty-0.0.75-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c6ccf34169821fe0d23e3360deeef981d217963412f1d087b9bdd32ec57f7a57", size = 12400533, upload-time = "2026-08-26T20:23:04.965Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/ae/a3b1a0f1cc83b7d258662cb98aa80a720c2e671d0e8fa0d17a4d5d057a7a/ty-0.0.55-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1e049f69ce65b3c269af67624607f435e1c32319786c1e453ef9611502f295", size = 11493517, upload-time = "2026-06-27T00:26:59.26Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/7f/1e284ea3d348d7be02f12d83bc22ed9ef193033f863f05b64db99027f141/ty-0.0.75-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842ebb41e9c6c334b40768704e20b1a69d5c6b08805b289d5e0e2565f49f2de1", size = 12420592, upload-time = "2026-08-26T20:23:07.427Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/9f/311ce39065a979ef40a9b847f685c8e02464e53adf1671e081eea90640ca/ty-0.0.55-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:631409975c681d5a280fc5a99b7b32e9e801f33be7567c6b42ec331362f59d7d", size = 11460590, upload-time = "2026-06-27T00:27:01.425Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/ab/d813271543370c47fd74b5118f2066ab32b0983e907b1821f3f9a6d0fa7f/ty-0.0.75-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7a5a723c5f1e0fab4ffbfe9bd95123a526ed48f206e5f25cb2161ca294007a", size = 12739219, upload-time = "2026-08-26T20:23:09.809Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/8f/3bf29aa77bd78aae48275153135a2052fa7d3ccdf1ecabeb99c8773abd66/ty-0.0.55-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e08cb0436e68b9351555ae8f2697138c9009b4d5b4ae4272232988b2a431a98f", size = 12098430, upload-time = "2026-06-27T00:27:03.596Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/5b/95b49cc5570fd92a7bf63732f649b31906158721e03c7fcb1b5be74ee3bf/ty-0.0.75-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54382f98e5da292fcd7104391afef5105c35bb2f312e29bea6f5fa419935255c", size = 13494046, upload-time = "2026-08-26T20:23:12.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6e/e88411a88240b94640bba06fb6d0d92b247fbeef47ee2bc71f39e58c2558/ty-0.0.55-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16c215ad9f823829409b94ee188cfaa4563f6e1384f6ce3fecb1db75f6c7cf7c", size = 12673086, upload-time = "2026-06-27T00:27:05.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/0d/502d2dd68173cf020e1ad2bdbab9544c86776de0b0e2ed15f8c2fe006e3d/ty-0.0.75-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac13b180dc2aade2cd243f56b01650e78bf091a2e522ad3bc947245d7837c613", size = 13938899, upload-time = "2026-08-26T20:23:14.764Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/7e/8f1762fb7f9245a68ba5ae338d73c59403ce57554e5d311b8bb55027b0ec/ty-0.0.55-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b510eb8f4032baf11b7aee2f1d53babc3b4ca03939b9cdcf6a9d15761d575188", size = 12242559, upload-time = "2026-06-27T00:27:07.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/5b/f3b12a25c07224456219fc2bd20db0ad7e40b304be0ff6aad728da0135f9/ty-0.0.75-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:752df7951a443219d7f1ff817e3723c85d428565ff449e08a7a93ba821661526", size = 13656711, upload-time = "2026-08-26T20:23:17.145Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/1f/143657daf2670d977dac83435f1fe03d4843efb798d8e1e75950e541aadd/ty-0.0.55-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc05e7959709c3b9b83aa627128a80446865e3c1a4882638dcff6d776dc34a", size = 12021409, upload-time = "2026-06-27T00:27:09.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/7b/f090ad306e2b15a07b332d647138c5264b89d9758855ecce8b8a10bcb153/ty-0.0.75-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd399feedf7cee816563c1baec45fc1c0b3c89f1ea42364920b688004b5b7da", size = 13093499, upload-time = "2026-08-26T20:23:19.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/30/69487c439dd1fad3a4a3d96f0a472193de297eaba6fc4b8ea687ce434ac2/ty-0.0.55-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:636e8e5078787b8c6916c94e1406719f10189a4ca6b37b813a5922ce5857a8c7", size = 12303807, upload-time = "2026-06-27T00:27:11.986Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/4b/f69b99aaaca0c7c65d5f114b186b26b21666f767b0c69eec99a2bdccc061/ty-0.0.75-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d7625f6f56c7dc1e873579fdc9e432a0e21e302afe847ab60704d2303442a92e", size = 13520580, upload-time = "2026-08-26T20:23:21.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/ca/cd88b6493dafc7db077f5e17c0438eb3af6e2d6d08f616dbb52a8ddfd567/ty-0.0.55-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ef7d6deaacb73fec603666b5471f1dc5a5699aa84e11a6d4d644dd07ca72121e", size = 11441263, upload-time = "2026-06-27T00:27:14.087Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/e7/692c5f905c0345a15d2255fc74066d660f030254ae8dcdaf33f5a5c2f279/ty-0.0.75-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:89e7d527e95a2534b70cae29e94c104b84082760ea05927d23bb87280969c104", size = 12524095, upload-time = "2026-08-26T20:23:24.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/fe/66b6915671653ab739f71e4f1b0528e69da64429b7ebf3840c625b6e43f2/ty-0.0.55-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9aeea0fe5875d3cf37faf0e44d0fdf9669335467749741b8fc0103916fb5cd32", size = 11484584, upload-time = "2026-06-27T00:27:16.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/9a/f42b12cf265ea95344bf554764c4791cfb273bdd628aadd7c209af7cadc3/ty-0.0.75-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0843f134440740706e01bee5f88f4cfc10e9b018bddb9e4ef4c12dc9fc0c9aef", size = 12756591, upload-time = "2026-08-26T20:23:26.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/4f/7a9c0bbac8b899e9f6c0ec110c6612f52e4db35f6bb17ddc0ef60384fa3e/ty-0.0.55-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b699c01310dbd2705a07c97c5f4aaeedef61bd9adeea2e7c46aed32401d3576", size = 11759309, upload-time = "2026-06-27T00:27:18.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/5e/9b180c133cb9cce48179a7d2bf9e1802d992aa8176a918e0e05205760b42/ty-0.0.75-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1bd0ec0e50ee1376875c88891efe6f549c3560fa5b2ddad79a425cd5a6218b9c", size = 12998754, upload-time = "2026-08-26T20:23:28.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/de/b6f8b1b69aa631b5716ef3f985c3b56de0e46c2499cc00d30c402b41f714/ty-0.0.55-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32cbeba543e46de2a983ec6d525d8b56514f7422bd1e1b57c44ccf7bfa72c38a", size = 12128755, upload-time = "2026-06-27T00:27:20.55Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/f6/3c6ef5dd550103e29905121c67fb96a374564f31a2f44c6faa1af98c2d61/ty-0.0.75-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f9eafd561f90110d5e29f589ec3e956c4686e2f6631348d99276436f5cbe4d1", size = 13316474, upload-time = "2026-08-26T20:23:30.857Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/90/a912531e51ee7e076b42972479290fa687c0f5e747b7e773f3033164acaa/ty-0.0.55-py3-none-win32.whl", hash = "sha256:52b968e24eb4f7a5c3bd251db1f99f60dd385890356d38fc619d84f1b423446a", size = 11117501, upload-time = "2026-06-27T00:27:22.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/52/12776337874c821076bd5368e352ccd9e67174790abe3b856f749cb3524b/ty-0.0.75-py3-none-win32.whl", hash = "sha256:05063a6fafe2154b794a7f964515d148e51acd186d72d4a3acd347ee9fa19336", size = 12316315, upload-time = "2026-08-26T20:23:33.528Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/7a/99d59843bf8908a7f9f4d13fda107dbad07b7faa28ecd7860eacf363fb1c/ty-0.0.55-py3-none-win_amd64.whl", hash = "sha256:bf39cbfdc0add44d94bd3fff1f53c351418d134b6a66b87efdb7876d7b7a2224", size = 12150106, upload-time = "2026-06-27T00:27:24.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/e6/bb51e16af5c7138c9f52f8f3d0a401a371c6798d092e3b74926f186a9814/ty-0.0.75-py3-none-win_amd64.whl", hash = "sha256:81cf1ba5f6b7536ad56747865214255d9bc8e80533a689dbb9ddeaad464b09f1", size = 12917267, upload-time = "2026-08-26T20:23:35.978Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/44/20987505cedf2a865b08482f0eabc181fd9599b062964057ec8a128a4296/ty-0.0.55-py3-none-win_arm64.whl", hash = "sha256:f7f3700a9a060e8f1af11e4fb63fafcaf272b041781f4ccdfda2b3b5c6c1e439", size = 11560157, upload-time = "2026-06-27T00:27:27.332Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/73/4542f829107468b5de4231af67f29927c093bfad11f3c1e5b2c08fb1206b/ty-0.0.75-py3-none-win_arm64.whl", hash = "sha256:541c9af5b7a0ad23d15ec315a7da81150833c359f48124ed3789ff25eacd6f42", size = 12711024, upload-time = "2026-08-26T20:23:38.159Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
+10
-17
@@ -39,7 +39,12 @@ You must pass these when invoking the graph as part of the configurable part of
|
|||||||
|
|
||||||
```python
|
```python
|
||||||
{"configurable": {"thread_id": "1"}} # valid config
|
{"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
|
### Serde
|
||||||
@@ -79,24 +84,12 @@ checkpoint = {
|
|||||||
"v": 4,
|
"v": 4,
|
||||||
"ts": "2024-07-31T20:14:19.804150+00:00",
|
"ts": "2024-07-31T20:14:19.804150+00:00",
|
||||||
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
"id": "1ef4f797-8335-6428-8001-8a1503f9b875",
|
||||||
"channel_values": {
|
"channel_values": {"my_key": "meow", "node": "node"},
|
||||||
"my_key": "meow",
|
"channel_versions": {"__start__": 2, "my_key": 3, "start:node": 3, "node": 3},
|
||||||
"node": "node"
|
|
||||||
},
|
|
||||||
"channel_versions": {
|
|
||||||
"__start__": 2,
|
|
||||||
"my_key": 3,
|
|
||||||
"start:node": 3,
|
|
||||||
"node": 3
|
|
||||||
},
|
|
||||||
"versions_seen": {
|
"versions_seen": {
|
||||||
"__input__": {},
|
"__input__": {},
|
||||||
"__start__": {
|
"__start__": {"__start__": 1},
|
||||||
"__start__": 1
|
"node": {"start:node": 2},
|
||||||
},
|
|
||||||
"node": {
|
|
||||||
"start:node": 2
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ from typing import (
|
|||||||
NamedTuple,
|
NamedTuple,
|
||||||
TypedDict,
|
TypedDict,
|
||||||
TypeVar,
|
TypeVar,
|
||||||
|
cast,
|
||||||
)
|
)
|
||||||
|
|
||||||
from langchain_core.runnables import RunnableConfig
|
from langchain_core.runnables import RunnableConfig
|
||||||
@@ -781,7 +782,7 @@ def get_serializable_checkpoint_metadata(
|
|||||||
"""Get checkpoint metadata in a backwards-compatible manner."""
|
"""Get checkpoint metadata in a backwards-compatible manner."""
|
||||||
checkpoint_metadata = get_checkpoint_metadata(config, metadata)
|
checkpoint_metadata = get_checkpoint_metadata(config, metadata)
|
||||||
if "writes" in checkpoint_metadata:
|
if "writes" in checkpoint_metadata:
|
||||||
checkpoint_metadata.pop("writes")
|
cast(dict[str, Any], checkpoint_metadata).pop("writes")
|
||||||
return checkpoint_metadata
|
return checkpoint_metadata
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -148,17 +148,16 @@ class InMemorySaver(
|
|||||||
whose stored blob is non-empty. Other channels keep walking until
|
whose stored blob is non-empty. Other channels keep walking until
|
||||||
they find their own terminator or hit the root.
|
they find their own terminator or hit the root.
|
||||||
|
|
||||||
Pre-delta plain-value blobs subsume their ancestor's pending
|
A blob is the value AT its ancestor, prior to the writes stored
|
||||||
writes (the value already includes them); `_DeltaSnapshot` blobs
|
under that same ancestor (those writes produce its child, which
|
||||||
do not (snapshot is the value AT that ancestor, prior to its own
|
is on the path to the target). This holds for `_DeltaSnapshot`
|
||||||
pending writes that produce the child).
|
blobs and for pre-delta plain values alike, so the seed
|
||||||
|
ancestor's own writes are always collected. Writes at ancestors
|
||||||
|
older than the seed are subsumed by the seed value and are never
|
||||||
|
reached — the walk terminates there.
|
||||||
"""
|
"""
|
||||||
if not channels:
|
if not channels:
|
||||||
return {}
|
return {}
|
||||||
# Imported lazily to avoid a hard checkpoint→serde-types coupling at
|
|
||||||
# module import; only this override needs the runtime check.
|
|
||||||
from langgraph.checkpoint.serde.types import _DeltaSnapshot
|
|
||||||
|
|
||||||
thread_id = config["configurable"]["thread_id"]
|
thread_id = config["configurable"]["thread_id"]
|
||||||
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
checkpoint_ns = config["configurable"].get("checkpoint_ns", "")
|
||||||
checkpoint_id = config["configurable"].get("checkpoint_id", "")
|
checkpoint_id = config["configurable"].get("checkpoint_id", "")
|
||||||
@@ -205,11 +204,6 @@ class InMemorySaver(
|
|||||||
):
|
):
|
||||||
if ch not in remaining:
|
if ch not in remaining:
|
||||||
continue
|
continue
|
||||||
blob_value = blob_value_by_ch.get(ch)
|
|
||||||
if blob_value is not None and not isinstance(
|
|
||||||
blob_value, _DeltaSnapshot
|
|
||||||
):
|
|
||||||
continue
|
|
||||||
collected_by_ch[ch].append(
|
collected_by_ch[ch].append(
|
||||||
(tid, ch, self.serde.loads_typed(serialized))
|
(tid, ch, self.serde.loads_typed(serialized))
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ Core types:
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from abc import ABC, abstractmethod
|
from abc import ABC, abstractmethod
|
||||||
from collections.abc import Iterable
|
from collections.abc import Iterable, Mapping
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
from typing import (
|
from typing import (
|
||||||
Any,
|
Any,
|
||||||
@@ -473,10 +473,10 @@ class PutOp(NamedTuple):
|
|||||||
the full path would effectively be `"documents/user123/report1"`
|
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 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.
|
Setting this to `None` signals that the item should be deleted.
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
@@ -857,7 +857,7 @@ class BaseStore(ABC):
|
|||||||
self,
|
self,
|
||||||
namespace: tuple[str, ...],
|
namespace: tuple[str, ...],
|
||||||
key: str,
|
key: str,
|
||||||
value: dict[str, Any],
|
value: Mapping[str, Any],
|
||||||
index: Literal[False] | list[str] | None = None,
|
index: Literal[False] | list[str] | None = None,
|
||||||
*,
|
*,
|
||||||
ttl: float | None | NotProvided = NOT_PROVIDED,
|
ttl: float | None | NotProvided = NOT_PROVIDED,
|
||||||
@@ -869,7 +869,7 @@ class BaseStore(ABC):
|
|||||||
Example: `("documents", "user123")`
|
Example: `("documents", "user123")`
|
||||||
key: Unique identifier within the namespace. Together with namespace forms
|
key: Unique identifier within the namespace. Together with namespace forms
|
||||||
the complete path to the item.
|
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.
|
and JSON-serializable values.
|
||||||
index: Controls how the item's fields are indexed for search:
|
index: Controls how the item's fields are indexed for search:
|
||||||
|
|
||||||
@@ -1110,7 +1110,7 @@ class BaseStore(ABC):
|
|||||||
self,
|
self,
|
||||||
namespace: tuple[str, ...],
|
namespace: tuple[str, ...],
|
||||||
key: str,
|
key: str,
|
||||||
value: dict[str, Any],
|
value: Mapping[str, Any],
|
||||||
index: Literal[False] | list[str] | None = None,
|
index: Literal[False] | list[str] | None = None,
|
||||||
*,
|
*,
|
||||||
ttl: float | None | NotProvided = NOT_PROVIDED,
|
ttl: float | None | NotProvided = NOT_PROVIDED,
|
||||||
@@ -1122,7 +1122,7 @@ class BaseStore(ABC):
|
|||||||
Example: `("documents", "user123")`
|
Example: `("documents", "user123")`
|
||||||
key: Unique identifier within the namespace. Together with namespace forms
|
key: Unique identifier within the namespace. Together with namespace forms
|
||||||
the complete path to the item.
|
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.
|
and JSON-serializable values.
|
||||||
index: Controls how the item's fields are indexed for search:
|
index: Controls how the item's fields are indexed for search:
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
import weakref
|
import weakref
|
||||||
from collections.abc import Callable, Iterable
|
from collections.abc import Callable, Iterable, Mapping
|
||||||
from typing import Any, Literal, TypeVar
|
from typing import Any, Literal, TypeVar
|
||||||
|
|
||||||
from langgraph.store.base import (
|
from langgraph.store.base import (
|
||||||
@@ -132,7 +132,7 @@ class AsyncBatchedBaseStore(BaseStore):
|
|||||||
self,
|
self,
|
||||||
namespace: tuple[str, ...],
|
namespace: tuple[str, ...],
|
||||||
key: str,
|
key: str,
|
||||||
value: dict[str, Any],
|
value: Mapping[str, Any],
|
||||||
index: Literal[False] | list[str] | None = None,
|
index: Literal[False] | list[str] | None = None,
|
||||||
*,
|
*,
|
||||||
ttl: float | None | NotProvided = NOT_PROVIDED,
|
ttl: float | None | NotProvided = NOT_PROVIDED,
|
||||||
@@ -231,7 +231,7 @@ class AsyncBatchedBaseStore(BaseStore):
|
|||||||
self,
|
self,
|
||||||
namespace: tuple[str, ...],
|
namespace: tuple[str, ...],
|
||||||
key: str,
|
key: str,
|
||||||
value: dict[str, Any],
|
value: Mapping[str, Any],
|
||||||
index: Literal[False] | list[str] | None = None,
|
index: Literal[False] | list[str] | None = None,
|
||||||
*,
|
*,
|
||||||
ttl: float | None | NotProvided = NOT_PROVIDED,
|
ttl: float | None | NotProvided = NOT_PROVIDED,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import functools
|
import functools
|
||||||
import json
|
import json
|
||||||
from collections.abc import Awaitable, Callable, Sequence
|
from collections.abc import Awaitable, Callable, Mapping, Sequence
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from langchain_core.embeddings import Embeddings
|
from langchain_core.embeddings import Embeddings
|
||||||
@@ -244,6 +244,9 @@ def get_text_at_path(obj: Any, path: str | list[str]) -> list[str]:
|
|||||||
- Multi-field selection: "{field1,field2}"
|
- Multi-field selection: "{field1,field2}"
|
||||||
- Nested paths in multi-field: "{field1,nested.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 == "$":
|
if not path or path == "$":
|
||||||
return [json.dumps(obj, sort_keys=True, ensure_ascii=False)]
|
return [json.dumps(obj, sort_keys=True, ensure_ascii=False)]
|
||||||
|
|
||||||
|
|||||||
@@ -408,7 +408,7 @@ class InMemoryStore(BaseStore):
|
|||||||
self._vectors[namespace].pop(key, None)
|
self._vectors[namespace].pop(key, None)
|
||||||
else:
|
else:
|
||||||
self._data[namespace][key] = Item(
|
self._data[namespace][key] = Item(
|
||||||
value=op.value,
|
value=dict(op.value),
|
||||||
key=key,
|
key=key,
|
||||||
namespace=namespace,
|
namespace=namespace,
|
||||||
created_at=datetime.now(timezone.utc),
|
created_at=datetime.now(timezone.utc),
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.1.1"
|
version = "4.2.0"
|
||||||
description = "Library with base interfaces for LangGraph checkpoint savers."
|
description = "Library with base interfaces for LangGraph checkpoint savers."
|
||||||
authors = []
|
authors = []
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@@ -59,9 +59,15 @@ lint.select = [
|
|||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
|
"PLC0415", # import-outside-top-level
|
||||||
|
"RUF100", # unused noqa directive
|
||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
]
|
]
|
||||||
lint.ignore = ["E501", "B008"]
|
lint.ignore = ["E501", "B008"]
|
||||||
|
# PLC0415 (import-outside-top-level) is enforced in tests only. Library code
|
||||||
|
# still has deferred imports that have not been reviewed, so it stays exempt
|
||||||
|
# for now.
|
||||||
|
lint.per-file-ignores = { "langgraph/**" = ["PLC0415"] }
|
||||||
target-version = "py310"
|
target-version = "py310"
|
||||||
|
|
||||||
[tool.ty.rules]
|
[tool.ty.rules]
|
||||||
|
|||||||
@@ -12,10 +12,14 @@ conformance = pytest.importorskip(
|
|||||||
|
|
||||||
@pytest.mark.asyncio
|
@pytest.mark.asyncio
|
||||||
async def test_delta_channel_conformance():
|
async def test_delta_channel_conformance():
|
||||||
from langgraph.checkpoint.conformance import validate
|
# Imported inside the test: the module-level importorskip above is what
|
||||||
from langgraph.checkpoint.conformance.initializer import checkpointer_test
|
# 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
|
from langgraph.checkpoint.memory import InMemorySaver # noqa: PLC0415
|
||||||
|
|
||||||
@checkpointer_test(name="InMemorySaver")
|
@checkpointer_test(name="InMemorySaver")
|
||||||
async def mem_saver():
|
async def mem_saver():
|
||||||
|
|||||||
@@ -307,8 +307,6 @@ class TestWithMsgpackAllowlistEncrypted:
|
|||||||
def loads_typed(self, data: tuple[str, bytes]) -> None:
|
def loads_typed(self, data: tuple[str, bytes]) -> None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
from langgraph.checkpoint.serde.base import CipherProtocol
|
|
||||||
|
|
||||||
class DummyCipher(CipherProtocol):
|
class DummyCipher(CipherProtocol):
|
||||||
def encrypt(self, plaintext: bytes) -> tuple[str, bytes]:
|
def encrypt(self, plaintext: bytes) -> tuple[str, bytes]:
|
||||||
return "dummy", plaintext
|
return "dummy", plaintext
|
||||||
|
|||||||
@@ -1,9 +1,12 @@
|
|||||||
import dataclasses
|
import dataclasses
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import os
|
||||||
import pathlib
|
import pathlib
|
||||||
|
import pickle
|
||||||
import re
|
import re
|
||||||
import sys
|
import sys
|
||||||
|
import tempfile
|
||||||
import uuid
|
import uuid
|
||||||
from collections import deque
|
from collections import deque
|
||||||
from datetime import date, datetime, time, timezone
|
from datetime import date, datetime, time, timezone
|
||||||
@@ -18,7 +21,7 @@ import ormsgpack
|
|||||||
import pandas as pd
|
import pandas as pd
|
||||||
import pytest
|
import pytest
|
||||||
from langchain_core.documents.base import Document
|
from langchain_core.documents.base import Document
|
||||||
from langchain_core.messages import HumanMessage
|
from langchain_core.messages import AIMessage, HumanMessage
|
||||||
from pydantic import BaseModel, SecretStr
|
from pydantic import BaseModel, SecretStr
|
||||||
from pydantic.v1 import BaseModel as BaseModelV1
|
from pydantic.v1 import BaseModel as BaseModelV1
|
||||||
from pydantic.v1 import SecretStr as SecretStrV1
|
from pydantic.v1 import SecretStr as SecretStrV1
|
||||||
@@ -341,7 +344,6 @@ def test_lc2_json_safe_type_revives_without_allowlist() -> None:
|
|||||||
constructor dicts. Resuming those threads must reconstruct proper BaseMessage objects
|
constructor dicts. Resuming those threads must reconstruct proper BaseMessage objects
|
||||||
rather than returning raw dicts that cause MESSAGE_COERCION_FAILURE in add_messages.
|
rather than returning raw dicts that cause MESSAGE_COERCION_FAILURE in add_messages.
|
||||||
"""
|
"""
|
||||||
from langchain_core.messages import AIMessage
|
|
||||||
|
|
||||||
serde = JsonPlusSerializer() # default: _allowed_json_modules=None
|
serde = JsonPlusSerializer() # default: _allowed_json_modules=None
|
||||||
|
|
||||||
@@ -410,7 +412,6 @@ def test_lc2_json_method_field_is_ignored() -> None:
|
|||||||
to that method: the result is whatever ``AIMessage(*args, **kwargs)`` would
|
to that method: the result is whatever ``AIMessage(*args, **kwargs)`` would
|
||||||
produce, which proves the default constructor ran instead of ``parse_raw``.
|
produce, which proves the default constructor ran instead of ``parse_raw``.
|
||||||
"""
|
"""
|
||||||
from langchain_core.messages import AIMessage
|
|
||||||
|
|
||||||
serde = JsonPlusSerializer()
|
serde = JsonPlusSerializer()
|
||||||
load = {
|
load = {
|
||||||
@@ -436,7 +437,6 @@ def test_lc2_json_method_field_is_ignored_for_allowlisted_types() -> None:
|
|||||||
method dispatch as a side effect. Revival is restricted to the default
|
method dispatch as a side effect. Revival is restricted to the default
|
||||||
constructor regardless of how the class reached the revival path.
|
constructor regardless of how the class reached the revival path.
|
||||||
"""
|
"""
|
||||||
from langchain_core.messages import AIMessage
|
|
||||||
|
|
||||||
serde = JsonPlusSerializer(
|
serde = JsonPlusSerializer(
|
||||||
allowed_json_modules=[("langchain_core.messages.ai", "AIMessage")]
|
allowed_json_modules=[("langchain_core.messages.ai", "AIMessage")]
|
||||||
@@ -455,7 +455,6 @@ def test_lc2_json_method_field_is_ignored_for_allowlisted_types() -> None:
|
|||||||
|
|
||||||
def test_lc2_json_safe_type_init_still_works() -> None:
|
def test_lc2_json_safe_type_init_still_works() -> None:
|
||||||
"""SAFE-type lc=2 revival without a `method` field still constructs the class."""
|
"""SAFE-type lc=2 revival without a `method` field still constructs the class."""
|
||||||
from langchain_core.messages import AIMessage
|
|
||||||
|
|
||||||
serde = JsonPlusSerializer()
|
serde = JsonPlusSerializer()
|
||||||
load = {
|
load = {
|
||||||
@@ -479,7 +478,6 @@ def test_lc2_json_legacy_pydantic_method_list_falls_back_to_default() -> None:
|
|||||||
this shape continue to revive correctly as long as the default constructor
|
this shape continue to revive correctly as long as the default constructor
|
||||||
accepts the serialized kwargs.
|
accepts the serialized kwargs.
|
||||||
"""
|
"""
|
||||||
from langchain_core.messages import AIMessage
|
|
||||||
|
|
||||||
serde = JsonPlusSerializer()
|
serde = JsonPlusSerializer()
|
||||||
load = {
|
load = {
|
||||||
@@ -551,9 +549,6 @@ def test_lc2_json_safe_type_pickle_payload_does_not_execute() -> None:
|
|||||||
With method dispatch removed from `_revive_lc2`, the gadget bytes are never
|
With method dispatch removed from `_revive_lc2`, the gadget bytes are never
|
||||||
passed to `parse_raw` and therefore never reach `pickle.loads`.
|
passed to `parse_raw` and therefore never reach `pickle.loads`.
|
||||||
"""
|
"""
|
||||||
import os
|
|
||||||
import pickle
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
marker = tempfile.NamedTemporaryFile(
|
marker = tempfile.NamedTemporaryFile(
|
||||||
prefix="lc2_block_proof_", suffix=".out", delete=False
|
prefix="lc2_block_proof_", suffix=".out", delete=False
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
@@ -523,7 +524,6 @@ class TestBaseFallbackGetChannelWrites:
|
|||||||
`threading.local()` guard would let whichever task set it first
|
`threading.local()` guard would let whichever task set it first
|
||||||
short-circuit the other to `writes=[]`.
|
short-circuit the other to `writes=[]`.
|
||||||
"""
|
"""
|
||||||
import asyncio
|
|
||||||
|
|
||||||
saver, thread_id, ns = self._build_saver_with_chain()
|
saver, thread_id, ns = self._build_saver_with_chain()
|
||||||
|
|
||||||
@@ -577,9 +577,19 @@ class TestPreDeltaBlobTerminator:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
def _build_mixed_thread(self) -> tuple[InMemorySaver, str, str, str, str]:
|
def _build_mixed_thread(self) -> tuple[InMemorySaver, str, str, str, str]:
|
||||||
"""Three-checkpoint chain: cp1 (pre-delta, blob=[A]), cp2 (delta,
|
"""Four-checkpoint chain spanning the migration boundary:
|
||||||
write=B), cp3 (delta, write=C). Reconstructing at cp3 must yield
|
|
||||||
seed=[A] + writes=[B, C].
|
* `cp0` — pre-delta ancestor OLDER than the seed. Its write
|
||||||
|
(`OLDER-WRITE`) is already folded into `cp1`'s stored value, so the
|
||||||
|
walk must terminate at `cp1` and never reach it.
|
||||||
|
* `cp1` — pre-delta, blob `["A"]`. That value is the state ENTERING
|
||||||
|
`cp1`; the write stored under `cp1` (`PRE-DELTA-WRITE`) is what
|
||||||
|
produced `cp2` and is NOT subsumed by the blob.
|
||||||
|
* `cp2` — delta-era, no stored value, write `B`.
|
||||||
|
* `cp3` — target, delta-era, write `PENDING-AT-TARGET`.
|
||||||
|
|
||||||
|
Reconstructing at `cp3` must yield seed `["A"]` plus writes
|
||||||
|
`["PRE-DELTA-WRITE", "B"]`.
|
||||||
|
|
||||||
Returns `(saver, thread_id, ns, channel, cp3_id)`.
|
Returns `(saver, thread_id, ns, channel, cp3_id)`.
|
||||||
"""
|
"""
|
||||||
@@ -587,16 +597,21 @@ class TestPreDeltaBlobTerminator:
|
|||||||
serde = JsonPlusSerializer()
|
serde = JsonPlusSerializer()
|
||||||
thread_id, ns, channel = "t1", "", "messages"
|
thread_id, ns, channel = "t1", "", "messages"
|
||||||
|
|
||||||
|
v0 = "00000000000000000000000000000000.0"
|
||||||
v1 = "00000000000000000000000000000001.0"
|
v1 = "00000000000000000000000000000001.0"
|
||||||
v2 = "00000000000000000000000000000002.0"
|
v2 = "00000000000000000000000000000002.0"
|
||||||
v3 = "00000000000000000000000000000003.0"
|
v3 = "00000000000000000000000000000003.0"
|
||||||
|
|
||||||
# Pre-delta: cp1 stored a real blob for the channel.
|
# Pre-delta: cp0 and cp1 stored real blobs for the channel.
|
||||||
|
saver.blobs[(thread_id, ns, channel, v0)] = serde.dumps_typed([])
|
||||||
saver.blobs[(thread_id, ns, channel, v1)] = serde.dumps_typed(["A"])
|
saver.blobs[(thread_id, ns, channel, v1)] = serde.dumps_typed(["A"])
|
||||||
# Delta-era: cp2 and cp3 store "empty"; real writes in checkpoint_writes.
|
# Delta-era: cp2 and cp3 store "empty"; real writes in checkpoint_writes.
|
||||||
saver.blobs[(thread_id, ns, channel, v2)] = ("empty", b"")
|
saver.blobs[(thread_id, ns, channel, v2)] = ("empty", b"")
|
||||||
saver.blobs[(thread_id, ns, channel, v3)] = ("empty", b"")
|
saver.blobs[(thread_id, ns, channel, v3)] = ("empty", b"")
|
||||||
|
|
||||||
|
cp0 = empty_checkpoint()
|
||||||
|
cp0["id"] = "cp0"
|
||||||
|
cp0["channel_versions"][channel] = v0
|
||||||
cp1 = empty_checkpoint()
|
cp1 = empty_checkpoint()
|
||||||
cp1["id"] = "cp1"
|
cp1["id"] = "cp1"
|
||||||
cp1["channel_versions"][channel] = v1
|
cp1["channel_versions"][channel] = v1
|
||||||
@@ -608,16 +623,24 @@ class TestPreDeltaBlobTerminator:
|
|||||||
cp3["channel_versions"][channel] = v3
|
cp3["channel_versions"][channel] = v3
|
||||||
|
|
||||||
saver.storage[thread_id][ns] = {
|
saver.storage[thread_id][ns] = {
|
||||||
"cp1": (serde.dumps_typed(cp1), serde.dumps_typed({}), None),
|
"cp0": (serde.dumps_typed(cp0), serde.dumps_typed({}), None),
|
||||||
|
"cp1": (serde.dumps_typed(cp1), serde.dumps_typed({}), "cp0"),
|
||||||
"cp2": (serde.dumps_typed(cp2), serde.dumps_typed({}), "cp1"),
|
"cp2": (serde.dumps_typed(cp2), serde.dumps_typed({}), "cp1"),
|
||||||
"cp3": (serde.dumps_typed(cp3), serde.dumps_typed({}), "cp2"),
|
"cp3": (serde.dumps_typed(cp3), serde.dumps_typed({}), "cp2"),
|
||||||
}
|
}
|
||||||
# Write under cp1 would be from the pre-delta era and MUST be ignored
|
# Write under cp0 is older than the seed — cp1's blob already folded
|
||||||
# (the blob already captures it). We add one and assert it is not
|
# it in, and the terminator must stop before reaching it.
|
||||||
# folded into the reconstructed result.
|
saver.writes[(thread_id, ns, "cp0")][("task0", 0)] = (
|
||||||
saver.writes[(thread_id, ns, "cp1")][("task0", 0)] = (
|
|
||||||
"task0",
|
"task0",
|
||||||
channel,
|
channel,
|
||||||
|
serde.dumps_typed("OLDER-WRITE"),
|
||||||
|
"",
|
||||||
|
)
|
||||||
|
# Write under cp1 postdates cp1's blob (it is what produced cp2, which
|
||||||
|
# stores no value of its own) and MUST be replayed.
|
||||||
|
saver.writes[(thread_id, ns, "cp1")][("task1", 0)] = (
|
||||||
|
"task1",
|
||||||
|
channel,
|
||||||
serde.dumps_typed("PRE-DELTA-WRITE"),
|
serde.dumps_typed("PRE-DELTA-WRITE"),
|
||||||
"",
|
"",
|
||||||
)
|
)
|
||||||
@@ -651,15 +674,19 @@ class TestPreDeltaBlobTerminator:
|
|||||||
|
|
||||||
# Seed came from the pre-delta blob at cp1.
|
# Seed came from the pre-delta blob at cp1.
|
||||||
assert result["seed"] == ["A"]
|
assert result["seed"] == ["A"]
|
||||||
# Delta-era writes from cp2 replay through the reducer on top of seed.
|
# The seed ancestor's own write and the delta-era write from cp2 both
|
||||||
# cp3 is the target — its own write is pending for the NEXT step and
|
# replay through the reducer on top of the seed, oldest first. cp3 is
|
||||||
# must be excluded.
|
# the target — its own write is pending for the NEXT step and must be
|
||||||
|
# excluded.
|
||||||
values = [v for _, _, v in result["writes"]]
|
values = [v for _, _, v in result["writes"]]
|
||||||
assert values == ["B"]
|
assert values == ["PRE-DELTA-WRITE", "B"]
|
||||||
|
|
||||||
def test_pre_delta_blob_terminates_walk_before_older_writes(self) -> None:
|
def test_seed_bounds_walk_without_dropping_its_own_writes(self) -> None:
|
||||||
"""Writes stored at the pre-delta ancestor itself must not be replayed
|
"""The seed terminator bounds the walk: writes at ancestors OLDER than
|
||||||
(the blob subsumes them)."""
|
the seed are already folded into the seed value and must not be
|
||||||
|
replayed. The seed ancestor's own write is not one of them — it
|
||||||
|
postdates the stored value and produced the next checkpoint.
|
||||||
|
"""
|
||||||
saver, thread_id, ns, channel, target = self._build_mixed_thread()
|
saver, thread_id, ns, channel, target = self._build_mixed_thread()
|
||||||
config: RunnableConfig = {
|
config: RunnableConfig = {
|
||||||
"configurable": {
|
"configurable": {
|
||||||
@@ -674,7 +701,9 @@ class TestPreDeltaBlobTerminator:
|
|||||||
]
|
]
|
||||||
|
|
||||||
values = [v for _, _, v in result["writes"]]
|
values = [v for _, _, v in result["writes"]]
|
||||||
# The pre-delta write under cp1 must not appear (the blob subsumes it).
|
# Older than the seed — subsumed by cp1's blob, so the walk stops first.
|
||||||
assert "PRE-DELTA-WRITE" not in values
|
assert "OLDER-WRITE" not in values
|
||||||
|
# Stored AT the seed ancestor — not subsumed, so it must be replayed.
|
||||||
|
assert "PRE-DELTA-WRITE" in values
|
||||||
# And the pending write at the target is never folded in.
|
# And the pending write at the target is never folded in.
|
||||||
assert "PENDING-AT-TARGET" not in values
|
assert "PENDING-AT-TARGET" not in values
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import json
|
import json
|
||||||
from collections.abc import Iterable
|
from collections import UserDict
|
||||||
|
from collections.abc import Iterable, Mapping
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
from types import MappingProxyType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
import pytest
|
import pytest
|
||||||
@@ -137,6 +139,18 @@ def test_get_text_at_path() -> None:
|
|||||||
assert get_text_at_path(nested_data, "nested[{invalid}]") == []
|
assert get_text_at_path(nested_data, "nested[{invalid}]") == []
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"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:
|
async def test_async_batch_store(mocker: MockerFixture) -> None:
|
||||||
abatch = mocker.stub()
|
abatch = mocker.stub()
|
||||||
|
|
||||||
|
|||||||
Generated
+53
-52
@@ -19,16 +19,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.12.1"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ 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 = [
|
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]]
|
[[package]]
|
||||||
@@ -149,11 +149,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespell"
|
name = "codespell"
|
||||||
version = "2.4.2"
|
version = "2.4.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/80/19/45e941380f69c042b43423513d201e6592346f992394347f5e7174c31407/codespell-2.4.3.tar.gz", hash = "sha256:cbe085e331227b37bb86ef8bddd08dc768c704ee9a07ca869852c093fa2793e2", size = 352773, upload-time = "2026-07-15T11:51:54.159Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
|
{ url = "https://files.pythonhosted.org/packages/8b/bf/bdb951d34eb169140b546f44be9ec4525d1acefb9eb5572071f5492b19fc/codespell-2.4.3-py3-none-any.whl", hash = "sha256:af2505b335e8573dbd2d384d1c4ef498f4006f4ba2d6fceca01e55b91f52628a", size = 340736, upload-time = "2026-07-15T11:51:52.925Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -183,7 +183,7 @@ name = "exceptiongroup"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
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" }
|
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 = [
|
wheels = [
|
||||||
@@ -268,9 +268,10 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.4.8"
|
version = "1.6.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "httpx" },
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
{ name = "langchain-protocol" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "langsmith" },
|
{ name = "langsmith" },
|
||||||
@@ -281,9 +282,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/12/e3/bea6d0080acf183332f24dcd74c208aee5857cf8f783c3fb0bd86027d8fb/langchain_core-1.4.8.tar.gz", hash = "sha256:5bf1f8411077c904182ad8f975943d36adcbf579c4e017b3a118b719229ebf9a", size = 957974, upload-time = "2026-06-18T19:39:23.636Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/90/12/aff76ca89c219ebe6f9dd3c5dbc4e3b1cf5450e9fc7037dccad23d45cd7a/langchain_core-1.6.1.tar.gz", hash = "sha256:1b156cb395aac4f009a8a1b38a574c7d948fe2d5f74c96e0d8a5017b4149e04f", size = 1003359, upload-time = "2026-08-27T19:31:14.956Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/d6/bdf6f0481cc57ef300d6b1eb48cf1400c0409be715d6eb3cabadd1142a09/langchain_core-1.4.8-py3-none-any.whl", hash = "sha256:d84c28b05e3ba8d4271d0827aad5b592ccdaaf986e76768c23503f0a2045e8aa", size = 557416, upload-time = "2026-06-18T19:39:21.902Z" },
|
{ url = "https://files.pythonhosted.org/packages/8e/25/f50dd65673c819aa33d3c34df58c115dbb6ec627d19f93e6e401dd0fc8d7/langchain_core-1.6.1-py3-none-any.whl", hash = "sha256:954a84132a5cb0435d27b910e336347b6744ecc18fbeef1e2de7029a0959841a", size = 571478, upload-time = "2026-08-27T19:31:13.34Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -300,7 +301,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.1.1"
|
version = "4.2.0"
|
||||||
source = { editable = "." }
|
source = { editable = "." }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -1124,14 +1125,14 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "redis"
|
name = "redis"
|
||||||
version = "8.0.1"
|
version = "8.1.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "async-timeout", marker = "python_full_version < '3.11.3'" },
|
{ 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 = [
|
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]]
|
[[package]]
|
||||||
@@ -1163,27 +1164,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.20"
|
version = "0.16.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/85/c8e12473c93018f92d19dd988a294202e1c27426c47ec4de53ffb847b8d8/ruff-0.16.5.tar.gz", hash = "sha256:1b88500f9ffbcab3dedb0082c9f9492e91ec3d618aac1236a3e0189938f7040b", size = 4912003, upload-time = "2026-08-27T16:34:18.258Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/b6/77c90a970fe2dae17a723acbd011043ea97c98d7deacccefdc4ba74ec512/ruff-0.16.5-py3-none-linux_armv6l.whl", hash = "sha256:12e5f673e774c35fbb62f288809c7653b73445f8ecec6b6063fd6ea3521aa14b", size = 10011941, upload-time = "2026-08-27T16:33:41.287Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/4b/46/6cf67cf6411885a1d6f7f6d801682f155536a85176d10b605e2ceffed8bd/ruff-0.16.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eda58a5802de40e7ed5b32b64e0b32539338cc6fcd2c78f61e3ad6a0d79f51c3", size = 10204049, upload-time = "2026-08-27T16:33:44.056Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/fd/c8720ca7a090abf0c2fef4abe8a5ef6e5127ed15196d8886ff75a2b370e2/ruff-0.16.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5ae9a7b9a8875131f40f8fe967cc86abf899779efd663cb7ce3d572d01da7eb", size = 9809037, upload-time = "2026-08-27T16:33:46.257Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/45/a684caacdedaca180f52bacccc40bf0789d2c5a7c75f25324853e9eaedb5/ruff-0.16.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b719b0a1f4d59710d283ab2965f621684a108a9e41da622e3b23f0326cd0025", size = 9964129, upload-time = "2026-08-27T16:33:48.352Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/5d2bcdaca6b5b93d1b4dfc166cd2aebf7680143a1b38a28759df13a94d31/ruff-0.16.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2298f2780ed1be0c5cb1361e32ab7b1467f3cce7dabe101d2210a314f2fe42e9", size = 9821518, upload-time = "2026-08-27T16:33:50.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/ff/011cce29accf9257d5974145b733fc653a37985ed6825413a3987cefbfe0/ruff-0.16.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:258f29035a2dd021e7861e631b227a5b3f14e50c1184c9a6a122c5f4576154d7", size = 10534835, upload-time = "2026-08-27T16:33:52.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/5a/f0cf109bada9bba0e96c90c21c9f9251803f57225c32d293327a03c710d6/ruff-0.16.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9a4f0432966834019c74d1b7e5c51224305d7713f3d7faf3e7451f1a3be3cde", size = 11252550, upload-time = "2026-08-27T16:33:54.521Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
|
{ url = "https://files.pythonhosted.org/packages/63/4d/1d481aaea2046c6a7ed7c291f9004c669cce3c087b6b376ed5b08271e3fe/ruff-0.16.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5eb3a8c3d0ade9cea42b591fd530368e8798380e30e0a308b85a5cf718f09ea", size = 10777949, upload-time = "2026-08-27T16:33:56.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/34/ee245ca55f64443233034b3d02b03236b19242004281247c079390b7facd/ruff-0.16.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0f69e191a13a3c9816f63163c88790cb12cd157bbbb384e9c44745702ab105", size = 10311656, upload-time = "2026-08-27T16:33:59.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/c33a333e341c0a2b96c715b52d89a606f5a34cd4ac493cd9b8d0187186b8/ruff-0.16.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0eeab41fbea2c42f98dfb9822cdccda9d24ba38d49f6dc945b5c236d48f0ef29", size = 10532125, upload-time = "2026-08-27T16:34:01.166Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/e1/a64cef78b40192497bb98a27a8aa8f2c98ee9ee15bc97f7712d94ef32937/ruff-0.16.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0768e9df4300713fff30733c87575f68b6f1d8de41184e505b7fdd9c0c95eaf", size = 10097648, upload-time = "2026-08-27T16:34:03.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/4e/4cdc9ed3c3e109d2f71e62572a37457298d7bc7501ec3138babb7ed32bbd/ruff-0.16.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:95cc70cdc7aa80c338de356279d2adbeb2de0f520b9ecd8aba75b94e95e02f91", size = 9829344, upload-time = "2026-08-27T16:34:05.134Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/4a/31ed35ce31729955fc583ee0d176d6e784c1290cb0b0a75cb2134c1ab72a/ruff-0.16.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d185c8398ded1bfd91c0c2cb258346307571eccc473a8490af8c3977399c384a", size = 10277117, upload-time = "2026-08-27T16:34:07.425Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a0/60356d86687b4b666d593df213f4dc3041750d024cb7bf2cfa81cfd65c2e/ruff-0.16.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fb8e3a3c4c6a784150a7ced53b015f4b253fc2bf97a610886419ead64b4756ef", size = 10711653, upload-time = "2026-08-27T16:34:09.712Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/20/656d67f5b25ca9bda4e02b1de25867b2954e1d19e03648060f167ad0f4cc/ruff-0.16.5-py3-none-win32.whl", hash = "sha256:288b0a5f080492fe5635db849f9e2e84aa3cce7b7f0e955997d416c507c76a26", size = 10034250, upload-time = "2026-08-27T16:34:11.8Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/42/ee8e68a207b9127fcde6c3d7e197def432f346cb1af159e1fa14ca0d1cdc/ruff-0.16.5-py3-none-win_amd64.whl", hash = "sha256:ddc6385fb2137f616357ca03d6c74f4be987f80fed4008566b754f6032b8546f", size = 10516714, upload-time = "2026-08-27T16:34:13.963Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
|
{ url = "https://files.pythonhosted.org/packages/73/e3/7df5a396e445b9ba49ce9a9437439a4d80042c61c0ade199abf8d16de1ac/ruff-0.16.5-py3-none-win_arm64.whl", hash = "sha256:a64abe90968719b851bb7cedffaa8753fbdbdadab483089682db623f3edc587e", size = 10391564, upload-time = "2026-08-27T16:34:16.064Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1260,27 +1261,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.55"
|
version = "0.0.75"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/48/f687c8d268e3581f2f104d1f2ac5944d5b5e841b3695c613b3f263e5bbf7/ty-0.0.55.tar.gz", hash = "sha256:88ca87073825a79a8327c550efcc86cec94344890244c5946f84c9e44a969f31", size = 6040230, upload-time = "2026-06-27T00:27:29.385Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/81/d0/d0c96f898d6974a4a3569ab3efdf9512c04ad99f9203effb55f72497fe97/ty-0.0.75.tar.gz", hash = "sha256:4c5eead33dfbf6e2ebb4f400f74b51ffc9bab702a6f23ddb648a1cbb740387e3", size = 6868326, upload-time = "2026-08-26T20:23:40.399Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/a3/1a90ba7e5a61c6d09adb92346ddba97668095fc257b577af433e5ac4f404/ty-0.0.55-py3-none-linux_armv6l.whl", hash = "sha256:31e83eef512d066542fe990fe1a3b814423abd1616376c54e48af7045b3e1749", size = 11677249, upload-time = "2026-06-27T00:26:52.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/6c/b12d03505f17581f0cfa3c12273fe34c1d67b36dfda1bc561a6bdc16512b/ty-0.0.75-py3-none-linux_armv6l.whl", hash = "sha256:e5409f50db2246fd4bd039d93d261e0cfa1daa554a4fb77256f91072c570349a", size = 12972606, upload-time = "2026-08-26T20:22:59.716Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/3a/669f9aa478c38243e213a2684db1502086026cfadc15bb1b29b7cbde030d/ty-0.0.55-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab4bca857950608fea73e269e2da369d43e6467131de85160d68e2fa466fa248", size = 11444180, upload-time = "2026-06-27T00:26:54.576Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/aa/30f11eecd9215a9f87e8fe8baaf48f3ce905f5d75b8e4aac70f0091f130c/ty-0.0.75-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5e7b8b3472fb9bb2eeab314984b265df08a7a9d518867a9e6020eebc06570be2", size = 12527158, upload-time = "2026-08-26T20:23:02.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/a4/6a4b2507a53ce6530c66c5b4fe0d58551eb1748ffa9e0696c32fdd55bbd4/ty-0.0.55-py3-none-macosx_11_0_arm64.whl", hash = "sha256:55032bfd31bf2c5355ee81bdc6407b144a1cc7ee41e5681dd1368e4cef2ba327", size = 10963134, upload-time = "2026-06-27T00:26:57.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/f2/11/7fd7001b0b5c6610bfbad7357e47d5fe6f82d4e84e94c53776a478f5e9f8/ty-0.0.75-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c6ccf34169821fe0d23e3360deeef981d217963412f1d087b9bdd32ec57f7a57", size = 12400533, upload-time = "2026-08-26T20:23:04.965Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/ae/a3b1a0f1cc83b7d258662cb98aa80a720c2e671d0e8fa0d17a4d5d057a7a/ty-0.0.55-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1e049f69ce65b3c269af67624607f435e1c32319786c1e453ef9611502f295", size = 11493517, upload-time = "2026-06-27T00:26:59.26Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/7f/1e284ea3d348d7be02f12d83bc22ed9ef193033f863f05b64db99027f141/ty-0.0.75-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842ebb41e9c6c334b40768704e20b1a69d5c6b08805b289d5e0e2565f49f2de1", size = 12420592, upload-time = "2026-08-26T20:23:07.427Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/9f/311ce39065a979ef40a9b847f685c8e02464e53adf1671e081eea90640ca/ty-0.0.55-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:631409975c681d5a280fc5a99b7b32e9e801f33be7567c6b42ec331362f59d7d", size = 11460590, upload-time = "2026-06-27T00:27:01.425Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/ab/d813271543370c47fd74b5118f2066ab32b0983e907b1821f3f9a6d0fa7f/ty-0.0.75-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7a5a723c5f1e0fab4ffbfe9bd95123a526ed48f206e5f25cb2161ca294007a", size = 12739219, upload-time = "2026-08-26T20:23:09.809Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/8f/3bf29aa77bd78aae48275153135a2052fa7d3ccdf1ecabeb99c8773abd66/ty-0.0.55-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e08cb0436e68b9351555ae8f2697138c9009b4d5b4ae4272232988b2a431a98f", size = 12098430, upload-time = "2026-06-27T00:27:03.596Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/5b/95b49cc5570fd92a7bf63732f649b31906158721e03c7fcb1b5be74ee3bf/ty-0.0.75-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54382f98e5da292fcd7104391afef5105c35bb2f312e29bea6f5fa419935255c", size = 13494046, upload-time = "2026-08-26T20:23:12.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6e/e88411a88240b94640bba06fb6d0d92b247fbeef47ee2bc71f39e58c2558/ty-0.0.55-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16c215ad9f823829409b94ee188cfaa4563f6e1384f6ce3fecb1db75f6c7cf7c", size = 12673086, upload-time = "2026-06-27T00:27:05.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/0d/502d2dd68173cf020e1ad2bdbab9544c86776de0b0e2ed15f8c2fe006e3d/ty-0.0.75-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac13b180dc2aade2cd243f56b01650e78bf091a2e522ad3bc947245d7837c613", size = 13938899, upload-time = "2026-08-26T20:23:14.764Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/7e/8f1762fb7f9245a68ba5ae338d73c59403ce57554e5d311b8bb55027b0ec/ty-0.0.55-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b510eb8f4032baf11b7aee2f1d53babc3b4ca03939b9cdcf6a9d15761d575188", size = 12242559, upload-time = "2026-06-27T00:27:07.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/5b/f3b12a25c07224456219fc2bd20db0ad7e40b304be0ff6aad728da0135f9/ty-0.0.75-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:752df7951a443219d7f1ff817e3723c85d428565ff449e08a7a93ba821661526", size = 13656711, upload-time = "2026-08-26T20:23:17.145Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/1f/143657daf2670d977dac83435f1fe03d4843efb798d8e1e75950e541aadd/ty-0.0.55-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc05e7959709c3b9b83aa627128a80446865e3c1a4882638dcff6d776dc34a", size = 12021409, upload-time = "2026-06-27T00:27:09.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/7b/f090ad306e2b15a07b332d647138c5264b89d9758855ecce8b8a10bcb153/ty-0.0.75-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd399feedf7cee816563c1baec45fc1c0b3c89f1ea42364920b688004b5b7da", size = 13093499, upload-time = "2026-08-26T20:23:19.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/30/69487c439dd1fad3a4a3d96f0a472193de297eaba6fc4b8ea687ce434ac2/ty-0.0.55-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:636e8e5078787b8c6916c94e1406719f10189a4ca6b37b813a5922ce5857a8c7", size = 12303807, upload-time = "2026-06-27T00:27:11.986Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/4b/f69b99aaaca0c7c65d5f114b186b26b21666f767b0c69eec99a2bdccc061/ty-0.0.75-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d7625f6f56c7dc1e873579fdc9e432a0e21e302afe847ab60704d2303442a92e", size = 13520580, upload-time = "2026-08-26T20:23:21.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/ca/cd88b6493dafc7db077f5e17c0438eb3af6e2d6d08f616dbb52a8ddfd567/ty-0.0.55-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ef7d6deaacb73fec603666b5471f1dc5a5699aa84e11a6d4d644dd07ca72121e", size = 11441263, upload-time = "2026-06-27T00:27:14.087Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/e7/692c5f905c0345a15d2255fc74066d660f030254ae8dcdaf33f5a5c2f279/ty-0.0.75-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:89e7d527e95a2534b70cae29e94c104b84082760ea05927d23bb87280969c104", size = 12524095, upload-time = "2026-08-26T20:23:24.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/fe/66b6915671653ab739f71e4f1b0528e69da64429b7ebf3840c625b6e43f2/ty-0.0.55-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9aeea0fe5875d3cf37faf0e44d0fdf9669335467749741b8fc0103916fb5cd32", size = 11484584, upload-time = "2026-06-27T00:27:16.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/9a/f42b12cf265ea95344bf554764c4791cfb273bdd628aadd7c209af7cadc3/ty-0.0.75-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0843f134440740706e01bee5f88f4cfc10e9b018bddb9e4ef4c12dc9fc0c9aef", size = 12756591, upload-time = "2026-08-26T20:23:26.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/4f/7a9c0bbac8b899e9f6c0ec110c6612f52e4db35f6bb17ddc0ef60384fa3e/ty-0.0.55-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b699c01310dbd2705a07c97c5f4aaeedef61bd9adeea2e7c46aed32401d3576", size = 11759309, upload-time = "2026-06-27T00:27:18.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/5e/9b180c133cb9cce48179a7d2bf9e1802d992aa8176a918e0e05205760b42/ty-0.0.75-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1bd0ec0e50ee1376875c88891efe6f549c3560fa5b2ddad79a425cd5a6218b9c", size = 12998754, upload-time = "2026-08-26T20:23:28.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/de/b6f8b1b69aa631b5716ef3f985c3b56de0e46c2499cc00d30c402b41f714/ty-0.0.55-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32cbeba543e46de2a983ec6d525d8b56514f7422bd1e1b57c44ccf7bfa72c38a", size = 12128755, upload-time = "2026-06-27T00:27:20.55Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/f6/3c6ef5dd550103e29905121c67fb96a374564f31a2f44c6faa1af98c2d61/ty-0.0.75-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f9eafd561f90110d5e29f589ec3e956c4686e2f6631348d99276436f5cbe4d1", size = 13316474, upload-time = "2026-08-26T20:23:30.857Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/90/a912531e51ee7e076b42972479290fa687c0f5e747b7e773f3033164acaa/ty-0.0.55-py3-none-win32.whl", hash = "sha256:52b968e24eb4f7a5c3bd251db1f99f60dd385890356d38fc619d84f1b423446a", size = 11117501, upload-time = "2026-06-27T00:27:22.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/52/12776337874c821076bd5368e352ccd9e67174790abe3b856f749cb3524b/ty-0.0.75-py3-none-win32.whl", hash = "sha256:05063a6fafe2154b794a7f964515d148e51acd186d72d4a3acd347ee9fa19336", size = 12316315, upload-time = "2026-08-26T20:23:33.528Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/7a/99d59843bf8908a7f9f4d13fda107dbad07b7faa28ecd7860eacf363fb1c/ty-0.0.55-py3-none-win_amd64.whl", hash = "sha256:bf39cbfdc0add44d94bd3fff1f53c351418d134b6a66b87efdb7876d7b7a2224", size = 12150106, upload-time = "2026-06-27T00:27:24.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/e6/bb51e16af5c7138c9f52f8f3d0a401a371c6798d092e3b74926f186a9814/ty-0.0.75-py3-none-win_amd64.whl", hash = "sha256:81cf1ba5f6b7536ad56747865214255d9bc8e80533a689dbb9ddeaad464b09f1", size = 12917267, upload-time = "2026-08-26T20:23:35.978Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/44/20987505cedf2a865b08482f0eabc181fd9599b062964057ec8a128a4296/ty-0.0.55-py3-none-win_arm64.whl", hash = "sha256:f7f3700a9a060e8f1af11e4fb63fafcaf272b041781f4ccdfda2b3b5c6c1e439", size = 11560157, upload-time = "2026-06-27T00:27:27.332Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/73/4542f829107468b5de4231af67f29927c093bfad11f3c1e5b2c08fb1206b/ty-0.0.75-py3-none-win_arm64.whl", hash = "sha256:541c9af5b7a0ad23d15ec315a7da81150833c359f48124ed3789ff25eacd6f42", size = 12711024, upload-time = "2026-08-26T20:23:38.159Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -103,6 +103,8 @@ The CLI uses a `langgraph.json` configuration file with these key settings:
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Git dependencies should use credential-free URLs. The CLI conservatively scans direct `langgraph.json` dependencies, common Python package files, uv project and lock files, and common Node.js package and lock files for HTTP Git URLs with userinfo. This check is not exhaustive: generated Docker builds can copy other files, including nested requirement or constraint files, into image layers without scanning them. For private dependencies, provide short-lived credentials through your build environment's secret-backed Git credential helper. Do not store credentials in copied files such as `langgraph.json` or `pip_config_file`.
|
||||||
|
|
||||||
See the [full documentation](https://reference.langchain.com/python/langgraph-cli) for detailed configuration options.
|
See the [full documentation](https://reference.langchain.com/python/langgraph-cli) for detailed configuration options.
|
||||||
|
|
||||||
## Development
|
## Development
|
||||||
|
|||||||
@@ -5,5 +5,5 @@ description = "Test for prerelease stuff"
|
|||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"langgraph==1.1.5"
|
"langgraph==1.2.6"
|
||||||
]
|
]
|
||||||
@@ -7,7 +7,7 @@ requires-python = ">=3.10"
|
|||||||
dependencies = [
|
dependencies = [
|
||||||
"langchain-openai==1.1.14",
|
"langchain-openai==1.1.14",
|
||||||
"langchain-anthropic==1.4.6",
|
"langchain-anthropic==1.4.6",
|
||||||
"langgraph==1.1.5"
|
"langgraph==1.2.6"
|
||||||
]
|
]
|
||||||
|
|
||||||
[tool.uv]
|
[tool.uv]
|
||||||
|
|||||||
Generated
-285
@@ -1,285 +0,0 @@
|
|||||||
# This file is automatically @generated by Poetry 2.0.0 and should not be changed by hand.
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "anyio"
|
|
||||||
version = "4.4.0"
|
|
||||||
description = "High level compatibility layer for multiple asynchronous event loop implementations"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "anyio-4.4.0-py3-none-any.whl", hash = "sha256:c1b2d8f46a8a812513012e1107cb0e68c17159a7a594208005a57dc776e1bdc7"},
|
|
||||||
{file = "anyio-4.4.0.tar.gz", hash = "sha256:5aadc6a1bbb7cdb0bede386cac5e2940f5e2ff3aa20277e991cf028e0585ce94"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""}
|
|
||||||
idna = ">=2.8"
|
|
||||||
sniffio = ">=1.1"
|
|
||||||
typing-extensions = {version = ">=4.1", markers = "python_version < \"3.11\""}
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphinx-rtd-theme"]
|
|
||||||
test = ["anyio[trio]", "coverage[toml] (>=7)", "exceptiongroup (>=1.2.0)", "hypothesis (>=4.0)", "psutil (>=5.9)", "pytest (>=7.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (>=0.17)"]
|
|
||||||
trio = ["trio (>=0.23)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "certifi"
|
|
||||||
version = "2024.7.4"
|
|
||||||
description = "Python package for providing Mozilla's CA Bundle."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.6"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"},
|
|
||||||
{file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "click"
|
|
||||||
version = "8.1.7"
|
|
||||||
description = "Composable command line interface toolkit"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"},
|
|
||||||
{file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
colorama = {version = "*", markers = "platform_system == \"Windows\""}
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "colorama"
|
|
||||||
version = "0.4.6"
|
|
||||||
description = "Cross-platform colored terminal text."
|
|
||||||
optional = false
|
|
||||||
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
|
|
||||||
groups = ["main"]
|
|
||||||
markers = "platform_system == \"Windows\""
|
|
||||||
files = [
|
|
||||||
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
|
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "exceptiongroup"
|
|
||||||
version = "1.2.1"
|
|
||||||
description = "Backport of PEP 654 (exception groups)"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
groups = ["main"]
|
|
||||||
markers = "python_version < \"3.11\""
|
|
||||||
files = [
|
|
||||||
{file = "exceptiongroup-1.2.1-py3-none-any.whl", hash = "sha256:5258b9ed329c5bbdd31a309f53cbfb0b155341807f6ff7606a1e801a891b29ad"},
|
|
||||||
{file = "exceptiongroup-1.2.1.tar.gz", hash = "sha256:a4785e48b045528f5bfe627b6ad554ff32def154f42372786903b7abcfe1aa16"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
test = ["pytest (>=6)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "h11"
|
|
||||||
version = "0.16.0"
|
|
||||||
description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"},
|
|
||||||
{file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "httpcore"
|
|
||||||
version = "1.0.9"
|
|
||||||
description = "A minimal low-level HTTP client."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"},
|
|
||||||
{file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
certifi = "*"
|
|
||||||
h11 = ">=0.16"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
asyncio = ["anyio (>=4.0,<5.0)"]
|
|
||||||
http2 = ["h2 (>=3,<5)"]
|
|
||||||
socks = ["socksio (==1.*)"]
|
|
||||||
trio = ["trio (>=0.22.0,<1.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "httpx"
|
|
||||||
version = "0.28.1"
|
|
||||||
description = "The next generation HTTP client."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"},
|
|
||||||
{file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
anyio = "*"
|
|
||||||
certifi = "*"
|
|
||||||
httpcore = "==1.*"
|
|
||||||
idna = "*"
|
|
||||||
|
|
||||||
[package.extras]
|
|
||||||
brotli = ["brotli", "brotlicffi"]
|
|
||||||
cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"]
|
|
||||||
http2 = ["h2 (>=3,<5)"]
|
|
||||||
socks = ["socksio (==1.*)"]
|
|
||||||
zstd = ["zstandard (>=0.18.0)"]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "httpx-sse"
|
|
||||||
version = "0.4.0"
|
|
||||||
description = "Consume Server-Sent Event (SSE) messages with HTTPX."
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "httpx-sse-0.4.0.tar.gz", hash = "sha256:1e81a3a3070ce322add1d3529ed42eb5f70817f45ed6ec915ab753f961139721"},
|
|
||||||
{file = "httpx_sse-0.4.0-py3-none-any.whl", hash = "sha256:f329af6eae57eaa2bdfd962b42524764af68075ea87370a2de920af5341e318f"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "idna"
|
|
||||||
version = "3.7"
|
|
||||||
description = "Internationalized Domain Names in Applications (IDNA)"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.5"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"},
|
|
||||||
{file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "langgraph-cli"
|
|
||||||
version = "0.1.52"
|
|
||||||
description = "CLI for interacting with LangGraph API"
|
|
||||||
optional = false
|
|
||||||
python-versions = "^3.9.0,<4.0"
|
|
||||||
groups = ["main"]
|
|
||||||
files = []
|
|
||||||
develop = true
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
click = "^8.1.7"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
type = "directory"
|
|
||||||
url = ".."
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "langgraph-sdk"
|
|
||||||
version = "0.1.29"
|
|
||||||
description = "SDK for interacting with LangGraph API"
|
|
||||||
optional = false
|
|
||||||
python-versions = "^3.9.0,<4.0"
|
|
||||||
groups = ["main"]
|
|
||||||
files = []
|
|
||||||
develop = true
|
|
||||||
|
|
||||||
[package.dependencies]
|
|
||||||
httpx = ">=0.25.2"
|
|
||||||
httpx-sse = ">=0.4.0"
|
|
||||||
orjson = ">=3.10.1"
|
|
||||||
|
|
||||||
[package.source]
|
|
||||||
type = "directory"
|
|
||||||
url = "../../sdk-py"
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "orjson"
|
|
||||||
version = "3.10.5"
|
|
||||||
description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:545d493c1f560d5ccfc134803ceb8955a14c3fcb47bbb4b2fee0232646d0b932"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4324929c2dd917598212bfd554757feca3e5e0fa60da08be11b4aa8b90013c1"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c13ca5e2ddded0ce6a927ea5a9f27cae77eee4c75547b4297252cb20c4d30e6"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b6c8e30adfa52c025f042a87f450a6b9ea29649d828e0fec4858ed5e6caecf63"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:338fd4f071b242f26e9ca802f443edc588fa4ab60bfa81f38beaedf42eda226c"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6970ed7a3126cfed873c5d21ece1cd5d6f83ca6c9afb71bbae21a0b034588d96"},
|
|
||||||
{file = "orjson-3.10.5-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:235dadefb793ad12f7fa11e98a480db1f7c6469ff9e3da5e73c7809c700d746b"},
|
|
||||||
{file = "orjson-3.10.5-cp310-none-win32.whl", hash = "sha256:be79e2393679eda6a590638abda16d167754393f5d0850dcbca2d0c3735cebe2"},
|
|
||||||
{file = "orjson-3.10.5-cp310-none-win_amd64.whl", hash = "sha256:c4a65310ccb5c9910c47b078ba78e2787cb3878cdded1702ac3d0da71ddc5228"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:cdf7365063e80899ae3a697def1277c17a7df7ccfc979990a403dfe77bb54d40"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b68742c469745d0e6ca5724506858f75e2f1e5b59a4315861f9e2b1df77775a"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7d10cc1b594951522e35a3463da19e899abe6ca95f3c84c69e9e901e0bd93d38"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dcbe82b35d1ac43b0d84072408330fd3295c2896973112d495e7234f7e3da2e1"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10c0eb7e0c75e1e486c7563fe231b40fdd658a035ae125c6ba651ca3b07936f5"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:53ed1c879b10de56f35daf06dbc4a0d9a5db98f6ee853c2dbd3ee9d13e6f302f"},
|
|
||||||
{file = "orjson-3.10.5-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:099e81a5975237fda3100f918839af95f42f981447ba8f47adb7b6a3cdb078fa"},
|
|
||||||
{file = "orjson-3.10.5-cp311-none-win32.whl", hash = "sha256:1146bf85ea37ac421594107195db8bc77104f74bc83e8ee21a2e58596bfb2f04"},
|
|
||||||
{file = "orjson-3.10.5-cp311-none-win_amd64.whl", hash = "sha256:36a10f43c5f3a55c2f680efe07aa93ef4a342d2960dd2b1b7ea2dd764fe4a37c"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:68f85ecae7af14a585a563ac741b0547a3f291de81cd1e20903e79f25170458f"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28afa96f496474ce60d3340fe8d9a263aa93ea01201cd2bad844c45cd21f5268"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cd684927af3e11b6e754df80b9ffafd9fb6adcaa9d3e8fdd5891be5a5cad51e"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d21b9983da032505f7050795e98b5d9eee0df903258951566ecc358f6696969"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ad1de7fef79736dde8c3554e75361ec351158a906d747bd901a52a5c9c8d24b"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2d97531cdfe9bdd76d492e69800afd97e5930cb0da6a825646667b2c6c6c0211"},
|
|
||||||
{file = "orjson-3.10.5-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d69858c32f09c3e1ce44b617b3ebba1aba030e777000ebdf72b0d8e365d0b2b3"},
|
|
||||||
{file = "orjson-3.10.5-cp312-none-win32.whl", hash = "sha256:64c9cc089f127e5875901ac05e5c25aa13cfa5dbbbd9602bda51e5c611d6e3e2"},
|
|
||||||
{file = "orjson-3.10.5-cp312-none-win_amd64.whl", hash = "sha256:b2efbd67feff8c1f7728937c0d7f6ca8c25ec81373dc8db4ef394c1d93d13dc5"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:03b565c3b93f5d6e001db48b747d31ea3819b89abf041ee10ac6988886d18e01"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:584c902ec19ab7928fd5add1783c909094cc53f31ac7acfada817b0847975f26"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5a35455cc0b0b3a1eaf67224035f5388591ec72b9b6136d66b49a553ce9eb1e6"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1670fe88b116c2745a3a30b0f099b699a02bb3482c2591514baf5433819e4f4d"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:185c394ef45b18b9a7d8e8f333606e2e8194a50c6e3c664215aae8cf42c5385e"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:ca0b3a94ac8d3886c9581b9f9de3ce858263865fdaa383fbc31c310b9eac07c9"},
|
|
||||||
{file = "orjson-3.10.5-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dfc91d4720d48e2a709e9c368d5125b4b5899dced34b5400c3837dadc7d6271b"},
|
|
||||||
{file = "orjson-3.10.5-cp38-none-win32.whl", hash = "sha256:c05f16701ab2a4ca146d0bca950af254cb7c02f3c01fca8efbbad82d23b3d9d4"},
|
|
||||||
{file = "orjson-3.10.5-cp38-none-win_amd64.whl", hash = "sha256:8a11d459338f96a9aa7f232ba95679fc0c7cedbd1b990d736467894210205c09"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:85c89131d7b3218db1b24c4abecea92fd6c7f9fab87441cfc342d3acc725d807"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb66215277a230c456f9038d5e2d84778141643207f85336ef8d2a9da26bd7ca"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:51bbcdea96cdefa4a9b4461e690c75ad4e33796530d182bdd5c38980202c134a"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dbead71dbe65f959b7bd8cf91e0e11d5338033eba34c114f69078d59827ee139"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5df58d206e78c40da118a8c14fc189207fffdcb1f21b3b4c9c0c18e839b5a214"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c4057c3b511bb8aef605616bd3f1f002a697c7e4da6adf095ca5b84c0fd43595"},
|
|
||||||
{file = "orjson-3.10.5-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b39e006b00c57125ab974362e740c14a0c6a66ff695bff44615dcf4a70ce2b86"},
|
|
||||||
{file = "orjson-3.10.5-cp39-none-win32.whl", hash = "sha256:eded5138cc565a9d618e111c6d5c2547bbdd951114eb822f7f6309e04db0fb47"},
|
|
||||||
{file = "orjson-3.10.5-cp39-none-win_amd64.whl", hash = "sha256:cc28e90a7cae7fcba2493953cff61da5a52950e78dc2dacfe931a317ee3d8de7"},
|
|
||||||
{file = "orjson-3.10.5.tar.gz", hash = "sha256:7a5baef8a4284405d96c90c7c62b755e9ef1ada84c2406c24a9ebec86b89f46d"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "sniffio"
|
|
||||||
version = "1.3.1"
|
|
||||||
description = "Sniff out which async library your code is running under"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
groups = ["main"]
|
|
||||||
files = [
|
|
||||||
{file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"},
|
|
||||||
{file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "typing-extensions"
|
|
||||||
version = "4.12.2"
|
|
||||||
description = "Backported and Experimental Type Hints for Python 3.8+"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.8"
|
|
||||||
groups = ["main"]
|
|
||||||
markers = "python_version < \"3.11\""
|
|
||||||
files = [
|
|
||||||
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
|
|
||||||
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[metadata]
|
|
||||||
lock-version = "2.1"
|
|
||||||
python-versions = "^3.9.0,<4.0"
|
|
||||||
content-hash = "ec5109729f30d2033a10a10e8f8d3ed94c7d96d5d31025b4815b0123664bb063"
|
|
||||||
@@ -21,28 +21,30 @@
|
|||||||
"test:all": "yarn test && yarn test:int && yarn lint:langgraph"
|
"test:all": "yarn test && yarn test:int && yarn lint:langgraph"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@langchain/core": "^1.2.1",
|
"@langchain/core": "^1.2.9",
|
||||||
"@langchain/langgraph": "^1.4.7"
|
"@langchain/langgraph": "^1.4.13"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"@langchain/langgraph-checkpoint": "1.0.4"
|
"@langchain/langgraph-checkpoint": "1.0.4",
|
||||||
|
"jest/**/js-yaml": "3.15.2",
|
||||||
|
"@eslint/eslintrc/js-yaml": "4.3.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/eslintrc": "^3.3.5",
|
"@eslint/eslintrc": "^3.3.6",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"@tsconfig/recommended": "^1.0.13",
|
"@tsconfig/recommended": "^1.0.13",
|
||||||
"@types/jest": "^30.0.0",
|
"@types/jest": "^30.0.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.62.1",
|
"@typescript-eslint/eslint-plugin": "^8.68.0",
|
||||||
"@typescript-eslint/parser": "^8.62.1",
|
"@typescript-eslint/parser": "^8.68.0",
|
||||||
"dotenv": "^17.4.2",
|
"dotenv": "^17.4.2",
|
||||||
"eslint": "^10.6.0",
|
"eslint": "^10.9.1",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-import": "^2.32.0",
|
"eslint-plugin-import": "^2.32.0",
|
||||||
"eslint-plugin-no-instanceof": "^1.0.1",
|
"eslint-plugin-no-instanceof": "^1.0.1",
|
||||||
"eslint-plugin-prettier": "^5.5.6",
|
"eslint-plugin-prettier": "^5.5.6",
|
||||||
"jest": "^30.4.2",
|
"jest": "^30.5.0",
|
||||||
"prettier": "^3.9.4",
|
"prettier": "^3.9.6",
|
||||||
"ts-jest": "^29.4.11",
|
"ts-jest": "^29.4.12",
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^7.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+998
-789
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,10 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@js-monorepo-example/shared": "*",
|
"@js-monorepo-example/shared": "*",
|
||||||
"@langchain/core": "^1.2.1",
|
"@langchain/core": "^1.2.9",
|
||||||
"@langchain/langgraph": "^1.4.7"
|
"@langchain/langgraph": "^1.4.13"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^7.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,6 +9,6 @@
|
|||||||
"clean": "rm -rf dist"
|
"clean": "rm -rf dist"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"typescript": "^6.0.3"
|
"typescript": "^7.0.2"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,18 +17,18 @@
|
|||||||
"lint": "eslint 'apps/**/*.ts' 'libs/**/*.ts'"
|
"lint": "eslint 'apps/**/*.ts' 'libs/**/*.ts'"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"turbo": "^2.10.2",
|
"turbo": "^2.10.12",
|
||||||
"typescript": "^6.0.3",
|
"typescript": "^7.0.2",
|
||||||
"@tsconfig/recommended": "^1.0.13",
|
"@tsconfig/recommended": "^1.0.13",
|
||||||
"@eslint/eslintrc": "^3.3.5",
|
"@eslint/eslintrc": "^3.3.6",
|
||||||
"@eslint/js": "^10.0.1",
|
"@eslint/js": "^10.0.1",
|
||||||
"eslint": "^10.6.0",
|
"eslint": "^10.9.1",
|
||||||
"eslint-config-prettier": "^10.1.8",
|
"eslint-config-prettier": "^10.1.8",
|
||||||
"eslint-plugin-import": "^2.27.5",
|
"eslint-plugin-import": "^2.27.5",
|
||||||
"eslint-plugin-no-instanceof": "^1.0.1",
|
"eslint-plugin-no-instanceof": "^1.0.1",
|
||||||
"eslint-plugin-prettier": "^5.5.6",
|
"eslint-plugin-prettier": "^5.5.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^8.62.1",
|
"@typescript-eslint/eslint-plugin": "^8.68.0",
|
||||||
"@typescript-eslint/parser": "^8.62.1",
|
"@typescript-eslint/parser": "^8.68.0",
|
||||||
"prettier": "^3.9.4"
|
"prettier": "^3.9.6"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,10 +28,10 @@
|
|||||||
debug "^4.3.1"
|
debug "^4.3.1"
|
||||||
minimatch "^10.2.4"
|
minimatch "^10.2.4"
|
||||||
|
|
||||||
"@eslint/config-helpers@^0.6.0":
|
"@eslint/config-helpers@^0.7.0":
|
||||||
version "0.6.0"
|
version "0.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.6.0.tgz#ef9a36881d39dfd5dbeac22b0da997fabfb08b03"
|
resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.7.0.tgz#09ee4aa07b73f059ec2d4c74bf4b2ff02b322377"
|
||||||
integrity sha512-ii6Bw9jJ2zi2cWA2Z+9/QZ/+3DX6kwaV5Q986D/CdP3Lap3w/pgQZ373FV7byY/i7L4IRH/G43I5dz1ClsCbpA==
|
integrity sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint/core" "^1.2.1"
|
"@eslint/core" "^1.2.1"
|
||||||
|
|
||||||
@@ -42,10 +42,10 @@
|
|||||||
dependencies:
|
dependencies:
|
||||||
"@types/json-schema" "^7.0.15"
|
"@types/json-schema" "^7.0.15"
|
||||||
|
|
||||||
"@eslint/eslintrc@^3.3.5":
|
"@eslint/eslintrc@^3.3.6":
|
||||||
version "3.3.5"
|
version "3.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.5.tgz#c131793cfc1a7b96f24a83e0a8bbd4b881558c60"
|
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.6.tgz#d22bfd6b3a7d8e1f2c0b2f2e6de111b53ec6e13e"
|
||||||
integrity sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==
|
integrity sha512-l2Ul9PrHsPCKcEY/ac7VgFj9D80C7S68sOKc618SyHDPK36s1XcFebXY0iTzUVn4Yq+YbwvSnDmCz9yxjX+QrA==
|
||||||
dependencies:
|
dependencies:
|
||||||
ajv "^6.14.0"
|
ajv "^6.14.0"
|
||||||
debug "^4.3.2"
|
debug "^4.3.2"
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
globals "^14.0.0"
|
globals "^14.0.0"
|
||||||
ignore "^5.2.0"
|
ignore "^5.2.0"
|
||||||
import-fresh "^3.2.1"
|
import-fresh "^3.2.1"
|
||||||
js-yaml "^4.1.1"
|
js-yaml "^4.3.0"
|
||||||
minimatch "^3.1.5"
|
minimatch "^3.1.5"
|
||||||
strip-json-comments "^3.1.1"
|
strip-json-comments "^3.1.1"
|
||||||
|
|
||||||
@@ -103,10 +103,10 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-9.0.0.tgz#4d0a3f127058043bf2e7ee169eaf30ed901302f3"
|
resolved "https://registry.yarnpkg.com/@isaacs/cliui/-/cliui-9.0.0.tgz#4d0a3f127058043bf2e7ee169eaf30ed901302f3"
|
||||||
integrity sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==
|
integrity sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==
|
||||||
|
|
||||||
"@langchain/core@^1.2.1":
|
"@langchain/core@^1.2.9":
|
||||||
version "1.2.1"
|
version "1.2.9"
|
||||||
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-1.2.1.tgz#46751258ee56a6ae47ae578eba7928d3995d11ed"
|
resolved "https://registry.yarnpkg.com/@langchain/core/-/core-1.2.9.tgz#4f5fb27ba07c51ce4fb8e1dc32eb36945737afa1"
|
||||||
integrity sha512-NNG/cC5FGuHDOAP56h0ddp8Rfk8p+othWzEK5RV9JIG6RvnF5vGa5r0AEGtKfQieed7s1kC42GuIzVOBvMBL/g==
|
integrity sha512-conzSEj9Zu1AyXJLXsSbgrtxtxinmI1yGqQ5CIJZSoV5rvv+yvQE/vgBnoySpBQ/bl3YPgj2FL/gbDjWykLSfg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@cfworker/json-schema" "^4.0.2"
|
"@cfworker/json-schema" "^4.0.2"
|
||||||
"@standard-schema/spec" "^1.1.0"
|
"@standard-schema/spec" "^1.1.0"
|
||||||
@@ -116,28 +116,28 @@
|
|||||||
p-queue "^6.6.2"
|
p-queue "^6.6.2"
|
||||||
zod "^3.25.76 || ^4"
|
zod "^3.25.76 || ^4"
|
||||||
|
|
||||||
"@langchain/langgraph-checkpoint@^1.1.3":
|
"@langchain/langgraph-checkpoint@^1.1.5":
|
||||||
version "1.1.3"
|
version "1.1.5"
|
||||||
resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-1.1.3.tgz#891f2f9a2e96cf2ab0920f9240f9ad1e0a86a4ab"
|
resolved "https://registry.yarnpkg.com/@langchain/langgraph-checkpoint/-/langgraph-checkpoint-1.1.5.tgz#c793177f9afcce31a1e9922f317f88fec1254282"
|
||||||
integrity sha512-wgzdQNeEsdw1e+4lvlj0tdq/RYR/k1vPin10g0ymGoehZDDgd9nvIllGXSXN4TFgF9sf5qQP/KTkOcLfeseIhA==
|
integrity sha512-BwDwl5VeTOh6CVuiIPgsUgfK51vTJDMSbFcSCUfjJWsl8/DPdK/mbv+ejxJstkSk/BlSPMP4JfXWcN6jD2ea2Q==
|
||||||
|
|
||||||
"@langchain/langgraph-sdk@~1.9.25":
|
"@langchain/langgraph-sdk@~1.10.0":
|
||||||
version "1.9.25"
|
version "1.10.0"
|
||||||
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-1.9.25.tgz#034baf46bb626313761f1006cb554e30d797e310"
|
resolved "https://registry.yarnpkg.com/@langchain/langgraph-sdk/-/langgraph-sdk-1.10.0.tgz#6ec1364a97caf615983161ae1f00b196897b9cd6"
|
||||||
integrity sha512-mRKW8zyQUaHox+HirRFMRrPqOvNbQI3xeXDt6kkk4PbBg77V92bsO1WzUVNrmJ81zCkvxyOrWSK8D6ioCj0a8A==
|
integrity sha512-cPPkh+hMNgeOaGtJRrqs1AjZde45cG2+Ma9Sc10wz2RyvT8SKToCKS+VvkS18SsLajnmq6/FKVmthq6rnUVYOw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@langchain/protocol" "^0.0.18"
|
"@langchain/protocol" "^0.0.19"
|
||||||
"@types/json-schema" "^7.0.15"
|
"@types/json-schema" "^7.0.15"
|
||||||
p-queue "^9.0.1"
|
p-queue "^9.0.1"
|
||||||
p-retry "^7.1.1"
|
p-retry "^7.1.1"
|
||||||
|
|
||||||
"@langchain/langgraph@^1.4.7":
|
"@langchain/langgraph@^1.4.13":
|
||||||
version "1.4.7"
|
version "1.4.13"
|
||||||
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-1.4.7.tgz#fed2157855ece936df27d812e6c5b21c515f7294"
|
resolved "https://registry.yarnpkg.com/@langchain/langgraph/-/langgraph-1.4.13.tgz#168ab4f05c212fd5ab4b2816bcad2e963b345101"
|
||||||
integrity sha512-2tcyf3QGC7v89kqSxMCtRvzg/3L/4yHtOaWC49A8KieCciWJs7LGaxHoPB6QRxXyUgyR+Zg9Q1ss/XJIE+JuSQ==
|
integrity sha512-LO1ak6jNQ9jR13tm7Ay4Yh2/otrH7LNVUwWTAI7WJigVdW5Fb6LuYSZUzVn4S7sVSiyVFfnrUcDTd8c7eAzPrQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@langchain/langgraph-checkpoint" "^1.1.3"
|
"@langchain/langgraph-checkpoint" "^1.1.5"
|
||||||
"@langchain/langgraph-sdk" "~1.9.25"
|
"@langchain/langgraph-sdk" "~1.10.0"
|
||||||
"@langchain/protocol" "^0.0.18"
|
"@langchain/protocol" "^0.0.18"
|
||||||
"@standard-schema/spec" "1.1.0"
|
"@standard-schema/spec" "1.1.0"
|
||||||
|
|
||||||
@@ -146,6 +146,11 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@langchain/protocol/-/protocol-0.0.18.tgz#6d96155e7263c958fbce6d4b7241b4725b72fbad"
|
resolved "https://registry.yarnpkg.com/@langchain/protocol/-/protocol-0.0.18.tgz#6d96155e7263c958fbce6d4b7241b4725b72fbad"
|
||||||
integrity sha512-XW1egQtPfsGI41w2AMZNFZrUIwFSQHTjVMZs0OaTpCAvht/QLoaPN8FQcsysMVypOhupG28J29yOorrc70otBQ==
|
integrity sha512-XW1egQtPfsGI41w2AMZNFZrUIwFSQHTjVMZs0OaTpCAvht/QLoaPN8FQcsysMVypOhupG28J29yOorrc70otBQ==
|
||||||
|
|
||||||
|
"@langchain/protocol@^0.0.19":
|
||||||
|
version "0.0.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/@langchain/protocol/-/protocol-0.0.19.tgz#7fe43fed115dc34b3b4c246e8d5283fbcbfab7b0"
|
||||||
|
integrity sha512-9hKcRrH7cBX6gfutdfXPoft1OCchHe4FEpALoDJMl5Qu+n/YG5ynZmyu8+8cxORlPwHBoKTxggvXz+76M1yX1Q==
|
||||||
|
|
||||||
"@pkgr/core@^0.3.6":
|
"@pkgr/core@^0.3.6":
|
||||||
version "0.3.6"
|
version "0.3.6"
|
||||||
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.3.6.tgz#3569708bd4be4d8870ba32bf1c456dac81600d97"
|
resolved "https://registry.yarnpkg.com/@pkgr/core/-/core-0.3.6.tgz#3569708bd4be4d8870ba32bf1c456dac81600d97"
|
||||||
@@ -166,35 +171,35 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.13.tgz#269fce3ad04ca70b93269ff44cca81b950f542da"
|
resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.13.tgz#269fce3ad04ca70b93269ff44cca81b950f542da"
|
||||||
integrity sha512-sySRuBfMKyKO/j2ZAhR8kSembhjuPEV4Ra3AHtmWLq51+iGaudr45crPSzNC5b7/Ctrh9dfUpBuTlYrH6rM58Q==
|
integrity sha512-sySRuBfMKyKO/j2ZAhR8kSembhjuPEV4Ra3AHtmWLq51+iGaudr45crPSzNC5b7/Ctrh9dfUpBuTlYrH6rM58Q==
|
||||||
|
|
||||||
"@turbo/darwin-64@2.10.2":
|
"@turbo/darwin-64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/darwin-64/-/darwin-64-2.10.2.tgz#224d47639e882a23985664f69278c61be37a2602"
|
resolved "https://registry.yarnpkg.com/@turbo/darwin-64/-/darwin-64-2.10.12.tgz#719ac12ae47caf7b4be855d672582cdbfde177ea"
|
||||||
integrity sha512-wBM3ObqOWnKUDmg7QfUFDkDHPFUAJmrYlYqmEM8jMPAPA/I6wRJIbWimeQUqhOiQ8xPKhzyWM+xaiUP0wz8FEQ==
|
integrity sha512-9nKgKoF6ZOUsM+or0OtNf+TTJSfGvDNP7ZFv/ZGWVwOSCkumyctQiTeHwB4UNljHTnC41AqylgbunLDHoccNrA==
|
||||||
|
|
||||||
"@turbo/darwin-arm64@2.10.2":
|
"@turbo/darwin-arm64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/darwin-arm64/-/darwin-arm64-2.10.2.tgz#c6f075855a10e87ee0f5db7582432906cf05b484"
|
resolved "https://registry.yarnpkg.com/@turbo/darwin-arm64/-/darwin-arm64-2.10.12.tgz#ac2d3dde3a2407f8359ca2e3152690280cff2714"
|
||||||
integrity sha512-/Cq0joWnuMjDPfhjbFP4sv+C/7gkQ415zlaO4XUzD5EZxbtrKgXKvuuydMvogG8GeUnN1aDltW71RlmEfpjbyw==
|
integrity sha512-H4Elb1jqTZVeIC9bbcNwjSzemZ6RegoTOVHeuV5Osirt2Z8UguTyisMEkvZjPVZgMeN9J4ERZBFad40tFnkb7w==
|
||||||
|
|
||||||
"@turbo/linux-64@2.10.2":
|
"@turbo/linux-64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/linux-64/-/linux-64-2.10.2.tgz#d4251e876fda269a3a9b1c02ee668dbb3187b2a5"
|
resolved "https://registry.yarnpkg.com/@turbo/linux-64/-/linux-64-2.10.12.tgz#264a0ec88a1f69f93cf57dab20be1b4c50bf226c"
|
||||||
integrity sha512-mMsf5IIhiKuceEXNstd25IbadjBXZ0amxzFOqliEzJX6HyeeHdBQPVSY583PWqYDyqM/FB8d5ZjkthfBSeuH3Q==
|
integrity sha512-lr7KIotukvjZwEXiFSYAeOH3BWzjFVBbSzTbv0fuGFsNukYyH0+g1hB5ecqnJkgkYU+KHEMG1edOhnjiKON1wQ==
|
||||||
|
|
||||||
"@turbo/linux-arm64@2.10.2":
|
"@turbo/linux-arm64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/linux-arm64/-/linux-arm64-2.10.2.tgz#2a68be00512a6874fe972dcf028a8f6d7b0b7620"
|
resolved "https://registry.yarnpkg.com/@turbo/linux-arm64/-/linux-arm64-2.10.12.tgz#3ee53d1f930d2bb65708e904971be0e765381e37"
|
||||||
integrity sha512-Wcng1i2kaKmXutmwxT9MUoYZvdaIekXAdlGr4+0TpgbhGLw7nDuEcRBFrxb5BbRoX1d1q8SpdRxLc45TvDZIdQ==
|
integrity sha512-f0pZDTtvzB5SuNwuXBaKbZHUCMCukgc8nMlHEuvLmj91Fzec+MEbr3cAvGNor5htEDqZnO6Lxt9N/GPI/77oGA==
|
||||||
|
|
||||||
"@turbo/windows-64@2.10.2":
|
"@turbo/windows-64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/windows-64/-/windows-64-2.10.2.tgz#f2233aec870c45d12b3dd8f1dfc767a042498151"
|
resolved "https://registry.yarnpkg.com/@turbo/windows-64/-/windows-64-2.10.12.tgz#ac0a0b7794f9a541e68e930383f48747f7e648ab"
|
||||||
integrity sha512-SsNhM7Ho7EpAdwtrJKBOic9Hso23vu6Dp0gAfLOvUFjPzurr/sGQlXZEvr6z89ne4RDOypTwz5CBDrixpMKtXw==
|
integrity sha512-SDOueJRjS/QcykWf2KCRtTLmIl5YMKsLbXkXQGhDwcTXvKXZiS5ih5lBl/gkwZIpYFjqA/rAlfMzlAFcVHNe0g==
|
||||||
|
|
||||||
"@turbo/windows-arm64@2.10.2":
|
"@turbo/windows-arm64@2.10.12":
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/@turbo/windows-arm64/-/windows-arm64-2.10.2.tgz#c7b8c5b7c30b1fb3b7dac33dda9cb161fe09f461"
|
resolved "https://registry.yarnpkg.com/@turbo/windows-arm64/-/windows-arm64-2.10.12.tgz#50eb6c20a20d0aab216d2b6aa13cc3100ea44106"
|
||||||
integrity sha512-Gf+S7ICAdimT/n02bOuVWKvhHnct/HYjZg3oBNIz5hZ9ZyWHbQim9J3P5Qip8WpX0ksxF7eaBVziJCuLnjhqDg==
|
integrity sha512-0i0mVUa4kKk+/B3RwEwPMf9CB+T7ul56hn5FFHNA4VUNTOoLBEd6aNf3FaKfCatDNZ6cicCEf6if9QUTVyzzcA==
|
||||||
|
|
||||||
"@types/esrecurse@^4.3.1":
|
"@types/esrecurse@^4.3.1":
|
||||||
version "4.3.1"
|
version "4.3.1"
|
||||||
@@ -216,102 +221,212 @@
|
|||||||
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee"
|
||||||
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==
|
||||||
|
|
||||||
"@typescript-eslint/eslint-plugin@^8.62.1":
|
"@typescript-eslint/eslint-plugin@^8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.62.1.tgz#1736dcdca6cae3359d818456a47d18b674761f7f"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.68.0.tgz#a8fbdb1cf49aafaf16071b646daad890151bd149"
|
||||||
integrity sha512-4EQM77WgVNxj7OkL/5b/D/xZsw00G577+UriYTC7JF5opcF3T2AuoeY7ueLaZgSVjSgCS6yOAJB5bRGLPSJUzA==
|
integrity sha512-WASHDpCm6qO5jj9g1a+8NiW5+GCkAyLReR56/4VruYmNgfUmqpxOfZ2Yfb8xGfJPWv5Qi6LSD8sXdces3vbp/Q==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/regexpp" "^4.12.2"
|
"@eslint-community/regexpp" "^4.12.2"
|
||||||
"@typescript-eslint/scope-manager" "8.62.1"
|
"@typescript-eslint/scope-manager" "8.68.0"
|
||||||
"@typescript-eslint/type-utils" "8.62.1"
|
"@typescript-eslint/type-utils" "8.68.0"
|
||||||
"@typescript-eslint/utils" "8.62.1"
|
"@typescript-eslint/utils" "8.68.0"
|
||||||
"@typescript-eslint/visitor-keys" "8.62.1"
|
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||||
ignore "^7.0.5"
|
ignore "^7.0.5"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/parser@^8.62.1":
|
"@typescript-eslint/parser@^8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.62.1.tgz#d3f7ba18f1bf78bfb7256fea021d1927b48e7080"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.68.0.tgz#61de31481354c50457bc9621a7ed746779f09ee7"
|
||||||
integrity sha512-sPhE4iHuJDSvoAiec+Ro8JyXw8f0ql13HFR82P99nCm9GwTEKG0KYLvDe6REk8BCXuit6vJAv/Yxg5ABaNS2rA==
|
integrity sha512-fHq2VC1kpyYfvEcbiMjOpySY4WS7voEp89yAThrHRX5sm9j2lzYppCb2umFMEed4fWcyeLjHxrz0mpjNBaBxMQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/scope-manager" "8.62.1"
|
"@typescript-eslint/scope-manager" "8.68.0"
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
"@typescript-eslint/typescript-estree" "8.62.1"
|
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||||
"@typescript-eslint/visitor-keys" "8.62.1"
|
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
|
|
||||||
"@typescript-eslint/project-service@8.62.1":
|
"@typescript-eslint/project-service@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.62.1.tgz#78d880eb1cf6859b5ec263d04f95403e9f90ae47"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.68.0.tgz#ea4b2869f59165c420cd7a4bbebc38039794e8cc"
|
||||||
integrity sha512-yQ3RgY5RkSBpsNS1Bx/JQEcA24FOSdfGktoyprAr5u18390UQdtVcfnEv4nIrIshNnavlVyZBKxQwT1fIAE6cg==
|
integrity sha512-5GQtWZCXFcFYux955pvoS02WLc49pXNlvIxocKjS0clvwo3in1RdlzVKyiqQH9vE5AKWFLTaUgeQkOrTS+0Qxw==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/tsconfig-utils" "^8.62.1"
|
"@typescript-eslint/tsconfig-utils" "^8.68.0"
|
||||||
"@typescript-eslint/types" "^8.62.1"
|
"@typescript-eslint/types" "^8.68.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
|
|
||||||
"@typescript-eslint/scope-manager@8.62.1":
|
"@typescript-eslint/scope-manager@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.62.1.tgz#7ee65e9a6eb3ccdc4816593a4ff38840306de88a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.68.0.tgz#e5a13a1159497faeab4e48279bf07576045b1499"
|
||||||
integrity sha512-r4d249KbQ1SFdpeStvob8Ih6aPPIzfqllPVOtvhve6ZcpuVcYo5/7zUWckKpHE7StASX4kTKZTLf0WQm/wPkcg==
|
integrity sha512-T5eXpcaJNg8bhjHJ8Rjp68Vq/QBteYtTKY8TZqVNPaUbuz0f6jI9t6aDkylwvalpAB9XTTFeFOjrjXAZ3YvmVA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
"@typescript-eslint/visitor-keys" "8.62.1"
|
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||||
|
|
||||||
"@typescript-eslint/tsconfig-utils@8.62.1", "@typescript-eslint/tsconfig-utils@^8.62.1":
|
"@typescript-eslint/tsconfig-utils@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.62.1.tgz#e2b5f24fe721044189cb7e81117c96d75979d627"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.68.0.tgz#594d7a3c5952055b3c431fc563ca7fd1defcce18"
|
||||||
integrity sha512-xadytJqX9vJVQ2fdQjkcIVigwaOJNWkpjdLt6cEQ+xPnrI1fkp+/jZE/I97k9KUjqtpd25i0HeyZf3T6dutv2g==
|
integrity sha512-F7zrGQfiJHojPwi8vhxZQC1tWtJzvL74cK/nqri2lk8YUXvYaYwl263xOJ69jDWPUk1hmcdoayFwk9lX09npVw==
|
||||||
|
|
||||||
"@typescript-eslint/type-utils@8.62.1":
|
"@typescript-eslint/tsconfig-utils@^8.68.0":
|
||||||
version "8.62.1"
|
version "8.69.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.62.1.tgz#ebd30b13bacb13070917259a23309cf644121f9a"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.69.0.tgz#d3b0ccc781ab252a90a0b3989b9d1eb85ab59469"
|
||||||
integrity sha512-aXM5xlqXiTxPibXB93cLAURfT3rlizf7uMXISCXy66Isr/9hISJx3yDsKl0L7lKa51b8JpFuNKby0/O0pEm9jg==
|
integrity sha512-xNqK7YTDZsLniQMV/4rpFR8Z5JlqeRvVjuG1YgF/mdPVH84HSD19L8CczMA0qg2RfwEV231GHH3VnToJDo4MfQ==
|
||||||
|
|
||||||
|
"@typescript-eslint/type-utils@8.68.0":
|
||||||
|
version "8.68.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.68.0.tgz#8f3e838dbd740909db27053857468cd037b00220"
|
||||||
|
integrity sha512-X77zqoY1EjeWGs/0JNxeaMfp5C5lIz4Tw8y66F1Ne8Faq6g424sBNYM6xBAqElfGZPLpWS+CZAp0DXyKDzWiHg==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
"@typescript-eslint/typescript-estree" "8.62.1"
|
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||||
"@typescript-eslint/utils" "8.62.1"
|
"@typescript-eslint/utils" "8.68.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/types@8.62.1", "@typescript-eslint/types@^8.62.1":
|
"@typescript-eslint/types@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.62.1.tgz#c58be954e483b2fc98275374d5bcb40b99842dc1"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.68.0.tgz#3f9d4e62fbe5728f09403cdc7b4d58af842ac1af"
|
||||||
integrity sha512-ooCzJFaf+Hg+uG6fA3NRFGuFjlfNlDhBthbv4ZPU/0elCAFUfnyXUvf/WOpHz/jYwSmvU2GkR2LtyUfy1AxZ1Q==
|
integrity sha512-9RnpsGJjrAllCMefGVVsImJM24YurhC0Q1h4UbvivtvOqXmR/vEJge2OoE++z9m6hyg8T1Q8t5SNT6tHSbrxcg==
|
||||||
|
|
||||||
"@typescript-eslint/typescript-estree@8.62.1":
|
"@typescript-eslint/types@^8.68.0":
|
||||||
version "8.62.1"
|
version "8.69.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.62.1.tgz#98c1bb17635d5b026b24193a8d29188ac64380ff"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.69.0.tgz#5d9ad3f707c2e4f70a2db540031104df3e63bcf5"
|
||||||
integrity sha512-xMcW9oP9u7fAMXYs9A65CVmtLQe2r//oXINHfi8HV+oiqhih17sbLdhXr4540YWlgpDKQdY854OL5ZrdCiQsAA==
|
integrity sha512-K3VrubUPhlo9VDBS6QdI8YB5j7ClpqLRdefcz6PFrhnwicehBweqQ9Evhl4l+FYz0HdDmMqIiSX0aldGRYtDCA==
|
||||||
|
|
||||||
|
"@typescript-eslint/typescript-estree@8.68.0":
|
||||||
|
version "8.68.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.68.0.tgz#bf4165029825138ac27231a3ff02923ecd977f38"
|
||||||
|
integrity sha512-OKKsD0tYmoNiU5PW2zehO1yO56jYOm1ShYlxon/Z0SJNidAkdVg86eg9ruRuoXf8xfnuWZGbwDsStkoXbZtIIA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/project-service" "8.62.1"
|
"@typescript-eslint/project-service" "8.68.0"
|
||||||
"@typescript-eslint/tsconfig-utils" "8.62.1"
|
"@typescript-eslint/tsconfig-utils" "8.68.0"
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
"@typescript-eslint/visitor-keys" "8.62.1"
|
"@typescript-eslint/visitor-keys" "8.68.0"
|
||||||
debug "^4.4.3"
|
debug "^4.4.3"
|
||||||
minimatch "^10.2.2"
|
minimatch "^10.2.2"
|
||||||
semver "^7.7.3"
|
semver "^7.7.3"
|
||||||
tinyglobby "^0.2.15"
|
tinyglobby "^0.2.15"
|
||||||
ts-api-utils "^2.5.0"
|
ts-api-utils "^2.5.0"
|
||||||
|
|
||||||
"@typescript-eslint/utils@8.62.1":
|
"@typescript-eslint/utils@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.62.1.tgz#1622b75c7e6df308181dd0b44855dc4228da0457"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.68.0.tgz#00547f2c8de8aca2a3c21752a9711f73206fd36d"
|
||||||
integrity sha512-sHtbPfuKNZCG+ih8SyjjucqRntSVmp8XgL5u6o9mAhiSn8ds5o/M/XdM0abweme2Tln3szOstOrZ9OXitvPh0g==
|
integrity sha512-PB5gJMMOg0Q5P1tsgWtEAqQacJXq0qEqRHDX/YJ4FaTMLfZPpHB3gjl2EJuiZyPABxmj4ZQYiY9m1bdAJ5y7tQ==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.9.1"
|
"@eslint-community/eslint-utils" "^4.9.1"
|
||||||
"@typescript-eslint/scope-manager" "8.62.1"
|
"@typescript-eslint/scope-manager" "8.68.0"
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
"@typescript-eslint/typescript-estree" "8.62.1"
|
"@typescript-eslint/typescript-estree" "8.68.0"
|
||||||
|
|
||||||
"@typescript-eslint/visitor-keys@8.62.1":
|
"@typescript-eslint/visitor-keys@8.68.0":
|
||||||
version "8.62.1"
|
version "8.68.0"
|
||||||
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.62.1.tgz#499657d77ffafb8a99eb1d6c97847ca430234722"
|
resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.68.0.tgz#78db3c9bb258a0309d9e2b1b617127c3a8fb1f54"
|
||||||
integrity sha512-4g3BLxfdTMy8iZG0MaBkadnlRrCJ74cQiFbyEVMrkwIoqdyaXXQM22cotDvrl4x28wgIZ9rEJRoM+mmhSJpJ1g==
|
integrity sha512-YR65gGdGvTUAWLldC3xLOvOzamdGzB4A5/N8rehEaHs3Zvoe39BhgY+u0SPch1OvrVTfLcc55wsSgK2NcnTS/A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@typescript-eslint/types" "8.62.1"
|
"@typescript-eslint/types" "8.68.0"
|
||||||
eslint-visitor-keys "^5.0.0"
|
eslint-visitor-keys "^5.0.0"
|
||||||
|
|
||||||
|
"@typescript/typescript-aix-ppc64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz#cdc7ce81d60f1e09034960ddfb1fb880d7a776b6"
|
||||||
|
integrity sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-darwin-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz#a55fdfcfa58df58d27db2237cde6a5c1e35a7235"
|
||||||
|
integrity sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==
|
||||||
|
|
||||||
|
"@typescript/typescript-darwin-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz#38d1c9172800a91d707bec64d2a370a016634db4"
|
||||||
|
integrity sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==
|
||||||
|
|
||||||
|
"@typescript/typescript-freebsd-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz#f1ff8810030b35d2b5be0db6a2dc650460ea94fa"
|
||||||
|
integrity sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-freebsd-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz#3d86b03f353c5b1ba95162eb6ce35533bfc294bd"
|
||||||
|
integrity sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz#d9334d96d6dac6ff85da9c865588948de939e91f"
|
||||||
|
integrity sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-arm@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz#ad94b41e1aee2a4dcc6a298c7b67c43345fde32e"
|
||||||
|
integrity sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-loong64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz#2965aee4fc873360139d893daafe6397a29138ad"
|
||||||
|
integrity sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-mips64el@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz#1a887a311bed3a833f80bfd4a9ed37c271936cf0"
|
||||||
|
integrity sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-ppc64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz#8b63c9b2f445b393eb4e43ec21da225dade3577d"
|
||||||
|
integrity sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-riscv64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz#b6e8a35c289b3ea97a92a41d461aaeed0d3b36e1"
|
||||||
|
integrity sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-s390x@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz#2ef96693be4861f6d17965427e5b009cbbed1a3e"
|
||||||
|
integrity sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==
|
||||||
|
|
||||||
|
"@typescript/typescript-linux-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz#73269cb0baba50aea0ca060445a6b88e583f1ce2"
|
||||||
|
integrity sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==
|
||||||
|
|
||||||
|
"@typescript/typescript-netbsd-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz#3a3649f97fafa210b4e6e3798c15e06605c8a901"
|
||||||
|
integrity sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==
|
||||||
|
|
||||||
|
"@typescript/typescript-netbsd-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz#47ec59491a40c470d2807dc4d2b825528fd979ab"
|
||||||
|
integrity sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==
|
||||||
|
|
||||||
|
"@typescript/typescript-openbsd-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz#796be8da0bd989d8a3fb96f2801e38a8365b4baf"
|
||||||
|
integrity sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-openbsd-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz#d37fe2a729eb942c076c454ee7f1815faf7d560f"
|
||||||
|
integrity sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==
|
||||||
|
|
||||||
|
"@typescript/typescript-sunos-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz#aba8d3464c3565a7044789baba96916bd4ab2c88"
|
||||||
|
integrity sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==
|
||||||
|
|
||||||
|
"@typescript/typescript-win32-arm64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz#b9de50a17196383f62620b5f9d0a2f34ad3b60d7"
|
||||||
|
integrity sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==
|
||||||
|
|
||||||
|
"@typescript/typescript-win32-x64@7.0.2":
|
||||||
|
version "7.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz#cf3b7b0d6ce5635daca4c8e01c189cdcde47ec3c"
|
||||||
|
integrity sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==
|
||||||
|
|
||||||
acorn-jsx@^5.3.2:
|
acorn-jsx@^5.3.2:
|
||||||
version "5.3.2"
|
version "5.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
|
||||||
@@ -447,10 +562,10 @@ brace-expansion@^1.1.7:
|
|||||||
balanced-match "^1.0.0"
|
balanced-match "^1.0.0"
|
||||||
concat-map "0.0.1"
|
concat-map "0.0.1"
|
||||||
|
|
||||||
brace-expansion@^5.0.2:
|
brace-expansion@^5.0.8:
|
||||||
version "5.0.2"
|
version "5.0.9"
|
||||||
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.2.tgz#b6c16d0791087af6c2bc463f52a8142046c06b6f"
|
resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.9.tgz#7c72438809b5fa5babf54199a1f1c281a6984fcf"
|
||||||
integrity sha512-Pdk8c9poy+YhOgVWw1JNN22/HcivgKWwpxKq04M/jTmHyCZn12WPJebZxdjSa5TmBqISrUSgNYU3eRORljfCCw==
|
integrity sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg==
|
||||||
dependencies:
|
dependencies:
|
||||||
balanced-match "^4.0.2"
|
balanced-match "^4.0.2"
|
||||||
|
|
||||||
@@ -771,15 +886,15 @@ eslint-visitor-keys@^5.0.0, eslint-visitor-keys@^5.0.1:
|
|||||||
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be"
|
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz#9e3c9489697824d2d4ce3a8ad12628f91e9f59be"
|
||||||
integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==
|
integrity sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==
|
||||||
|
|
||||||
eslint@^10.6.0:
|
eslint@^10.9.1:
|
||||||
version "10.6.0"
|
version "10.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.6.0.tgz#e1b4059c582be950c7088c9b55f984738b243c27"
|
resolved "https://registry.yarnpkg.com/eslint/-/eslint-10.9.1.tgz#409da5c41a5536d5a849f8555a18ca7ef1eb963b"
|
||||||
integrity sha512-6lVbcqSodALYo+4ELD0heG6lFiFxnLMuLkiMi2qV8LMp54N8tE8FT1GMH+ev4Ti00nFjNze2+Su6DsV5OQW3Dg==
|
integrity sha512-9VaAkDURekixUQJy0oJYl2DcN6oKMfxay7XzaGYAWQwsb6qfKf+x76R2k1L8kb1boc+FyCAaTA9GmiKaaiaF+A==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@eslint-community/eslint-utils" "^4.8.0"
|
"@eslint-community/eslint-utils" "^4.8.0"
|
||||||
"@eslint-community/regexpp" "^4.12.2"
|
"@eslint-community/regexpp" "^4.12.2"
|
||||||
"@eslint/config-array" "^0.23.5"
|
"@eslint/config-array" "^0.23.5"
|
||||||
"@eslint/config-helpers" "^0.6.0"
|
"@eslint/config-helpers" "^0.7.0"
|
||||||
"@eslint/core" "^1.2.1"
|
"@eslint/core" "^1.2.1"
|
||||||
"@eslint/plugin-kit" "^0.7.2"
|
"@eslint/plugin-kit" "^0.7.2"
|
||||||
"@humanfs/node" "^0.16.6"
|
"@humanfs/node" "^0.16.6"
|
||||||
@@ -803,7 +918,7 @@ eslint@^10.6.0:
|
|||||||
imurmurhash "^0.1.4"
|
imurmurhash "^0.1.4"
|
||||||
is-glob "^4.0.0"
|
is-glob "^4.0.0"
|
||||||
json-stable-stringify-without-jsonify "^1.0.1"
|
json-stable-stringify-without-jsonify "^1.0.1"
|
||||||
minimatch "^10.2.4"
|
minimatch "^10.2.5"
|
||||||
natural-compare "^1.4.0"
|
natural-compare "^1.4.0"
|
||||||
optionator "^0.9.3"
|
optionator "^0.9.3"
|
||||||
|
|
||||||
@@ -1275,10 +1390,10 @@ js-tiktoken@^1.0.12:
|
|||||||
dependencies:
|
dependencies:
|
||||||
base64-js "^1.5.1"
|
base64-js "^1.5.1"
|
||||||
|
|
||||||
js-yaml@^4.1.1:
|
js-yaml@^4.3.0:
|
||||||
version "4.3.0"
|
version "4.3.2"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.0.tgz#d1900572a7f7cf0b5f540c83673e60bad3436592"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.3.2.tgz#8e44fb14a2643c59726bb15787b5f1512cb3d3fb"
|
||||||
integrity sha512-1td788aAnnZ5qs7V2QIRl1owjtYpbKt749Y3xauqQgwIIGF/xXWz1wMTEBx5O3LK3lXLVuqXPdPxj2BoFHaW9Q==
|
integrity sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==
|
||||||
dependencies:
|
dependencies:
|
||||||
argparse "^2.0.1"
|
argparse "^2.0.1"
|
||||||
|
|
||||||
@@ -1338,12 +1453,12 @@ math-intrinsics@^1.1.0:
|
|||||||
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9"
|
||||||
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==
|
||||||
|
|
||||||
minimatch@^10.2.2, minimatch@^10.2.4:
|
minimatch@^10.2.2, minimatch@^10.2.4, minimatch@^10.2.5:
|
||||||
version "10.2.4"
|
version "10.2.6"
|
||||||
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.4.tgz#465b3accbd0218b8281f5301e27cedc697f96fde"
|
resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.6.tgz#fd956bbe0b77241e9f15ac5dccb1c638060968ef"
|
||||||
integrity sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==
|
integrity sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==
|
||||||
dependencies:
|
dependencies:
|
||||||
brace-expansion "^5.0.2"
|
brace-expansion "^5.0.8"
|
||||||
|
|
||||||
minimatch@^3.1.2, minimatch@^3.1.5:
|
minimatch@^3.1.2, minimatch@^3.1.5:
|
||||||
version "3.1.5"
|
version "3.1.5"
|
||||||
@@ -1542,10 +1657,10 @@ prettier-linter-helpers@^1.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
fast-diff "^1.1.2"
|
fast-diff "^1.1.2"
|
||||||
|
|
||||||
prettier@^3.9.4:
|
prettier@^3.9.6:
|
||||||
version "3.9.4"
|
version "3.9.6"
|
||||||
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.9.4.tgz#a9c477cf1614376bd1f6bbc593d8c0d414bcec87"
|
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.9.6.tgz#b3ea5146515d40fc53f18aa63f74dfab1e10dbf6"
|
||||||
integrity sha512-yWG/o/4oJfo036EKAfK6ACAoDOfHeRHx4tuxkfBZiauURiaSmYwlpOr5LQqKtIkRD2z1PLteme2WoxEnj4tHTg==
|
integrity sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==
|
||||||
|
|
||||||
punycode@^2.1.0:
|
punycode@^2.1.0:
|
||||||
version "2.3.1"
|
version "2.3.1"
|
||||||
@@ -1798,17 +1913,17 @@ tsconfig-paths@^3.15.0:
|
|||||||
minimist "^1.2.6"
|
minimist "^1.2.6"
|
||||||
strip-bom "^3.0.0"
|
strip-bom "^3.0.0"
|
||||||
|
|
||||||
turbo@^2.10.2:
|
turbo@^2.10.12:
|
||||||
version "2.10.2"
|
version "2.10.12"
|
||||||
resolved "https://registry.yarnpkg.com/turbo/-/turbo-2.10.2.tgz#7b8993242d550e3adf7f3245b231f663e5300ebf"
|
resolved "https://registry.yarnpkg.com/turbo/-/turbo-2.10.12.tgz#22f552bd88182d58365960a02e5f45e628fb965b"
|
||||||
integrity sha512-wTExrNrRjB8qzIcg+ZLm0A3GFNLDsWNwdS/RBXB0FPrBDyzk3i96Yx+TxWZC7a0k1SIreFB8ciUbxjmEqTH8IQ==
|
integrity sha512-AswgMPnpOoaVZHrrSBejETzEbuIA69OVGwfkHwfrY0A23VjWXBANzgq9+OymWOHAIArB7D1+1z498WY8fGg1Jw==
|
||||||
optionalDependencies:
|
optionalDependencies:
|
||||||
"@turbo/darwin-64" "2.10.2"
|
"@turbo/darwin-64" "2.10.12"
|
||||||
"@turbo/darwin-arm64" "2.10.2"
|
"@turbo/darwin-arm64" "2.10.12"
|
||||||
"@turbo/linux-64" "2.10.2"
|
"@turbo/linux-64" "2.10.12"
|
||||||
"@turbo/linux-arm64" "2.10.2"
|
"@turbo/linux-arm64" "2.10.12"
|
||||||
"@turbo/windows-64" "2.10.2"
|
"@turbo/windows-64" "2.10.12"
|
||||||
"@turbo/windows-arm64" "2.10.2"
|
"@turbo/windows-arm64" "2.10.12"
|
||||||
|
|
||||||
type-check@^0.4.0, type-check@~0.4.0:
|
type-check@^0.4.0, type-check@~0.4.0:
|
||||||
version "0.4.0"
|
version "0.4.0"
|
||||||
@@ -1862,10 +1977,31 @@ typed-array-length@^1.0.7:
|
|||||||
possible-typed-array-names "^1.0.0"
|
possible-typed-array-names "^1.0.0"
|
||||||
reflect.getprototypeof "^1.0.6"
|
reflect.getprototypeof "^1.0.6"
|
||||||
|
|
||||||
typescript@^6.0.3:
|
typescript@^7.0.2:
|
||||||
version "6.0.3"
|
version "7.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21"
|
resolved "https://registry.yarnpkg.com/typescript/-/typescript-7.0.2.tgz#9ec773d7954a8c182c17cc5bbd575aa28bc51582"
|
||||||
integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==
|
integrity sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==
|
||||||
|
optionalDependencies:
|
||||||
|
"@typescript/typescript-aix-ppc64" "7.0.2"
|
||||||
|
"@typescript/typescript-darwin-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-darwin-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-freebsd-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-freebsd-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-arm" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-loong64" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-mips64el" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-ppc64" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-riscv64" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-s390x" "7.0.2"
|
||||||
|
"@typescript/typescript-linux-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-netbsd-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-netbsd-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-openbsd-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-openbsd-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-sunos-x64" "7.0.2"
|
||||||
|
"@typescript/typescript-win32-arm64" "7.0.2"
|
||||||
|
"@typescript/typescript-win32-x64" "7.0.2"
|
||||||
|
|
||||||
unbox-primitive@^1.1.0:
|
unbox-primitive@^1.1.0:
|
||||||
version "1.1.0"
|
version "1.1.0"
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
__version__ = "0.4.31"
|
__version__ = "0.4.32"
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import re
|
|||||||
import shlex
|
import shlex
|
||||||
import textwrap
|
import textwrap
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from collections.abc import Iterable
|
||||||
from typing import Literal, NamedTuple
|
from typing import Literal, NamedTuple
|
||||||
|
|
||||||
import click
|
import click
|
||||||
@@ -36,6 +37,10 @@ DISALLOWED_BUILD_COMMAND_CHARS = [
|
|||||||
# This blocks background execution (cmd &) while allowing command
|
# This blocks background execution (cmd &) while allowing command
|
||||||
# chaining (cmd1 && cmd2) which is common in build commands.
|
# chaining (cmd1 && cmd2) which is common in build commands.
|
||||||
_SINGLE_AMPERSAND_RE = re.compile(r"(?<!&)&(?:&&)*(?!&)")
|
_SINGLE_AMPERSAND_RE = re.compile(r"(?<!&)&(?:&&)*(?!&)")
|
||||||
|
_GIT_HTTP_AUTHORITY_RES = (
|
||||||
|
re.compile(r"git\+https?://(?P<authority>[^/\s\"']+)", re.I),
|
||||||
|
re.compile(r"\bgit\s*=\s*[\"']https?://(?P<authority>[^/\s\"']+)", re.I),
|
||||||
|
)
|
||||||
_API_VERSION_PATTERN = re.compile(
|
_API_VERSION_PATTERN = re.compile(
|
||||||
r"^(?P<major>\d+)"
|
r"^(?P<major>\d+)"
|
||||||
r"(?:\.(?P<minor>\d+))?"
|
r"(?:\.(?P<minor>\d+))?"
|
||||||
@@ -78,6 +83,62 @@ def has_disallowed_build_command_content(command: str) -> bool:
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
def _has_git_http_url_userinfo(dependency: str) -> bool:
|
||||||
|
"""Check whether a Git HTTP URL contains userinfo."""
|
||||||
|
return any(
|
||||||
|
"@" in match.group("authority")
|
||||||
|
for pattern in _GIT_HTTP_AUTHORITY_RES
|
||||||
|
for match in pattern.finditer(dependency)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_git_http_url_userinfo(
|
||||||
|
values: Iterable[str], *, source: pathlib.Path | None = None
|
||||||
|
) -> None:
|
||||||
|
"""Reject credential-bearing Git HTTP URLs without echoing their values."""
|
||||||
|
if not any(_has_git_http_url_userinfo(value) for value in values):
|
||||||
|
return
|
||||||
|
message = (
|
||||||
|
"Git dependency URLs must not contain credentials or other URL "
|
||||||
|
"userinfo because generated Dockerfiles and image layers can retain "
|
||||||
|
"them. Use a credential-free Git URL and provide short-lived "
|
||||||
|
"credentials through your build environment's secret-backed Git "
|
||||||
|
"credential helper."
|
||||||
|
)
|
||||||
|
if source is not None:
|
||||||
|
message += f" Found in: {source}"
|
||||||
|
raise click.UsageError(message)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_git_http_url_userinfo_files(paths: Iterable[pathlib.Path]) -> None:
|
||||||
|
"""Reject credential-bearing Git HTTP URLs in dependency files."""
|
||||||
|
for path in paths:
|
||||||
|
path = path.resolve()
|
||||||
|
if not path.is_file():
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
contents = path.read_text(encoding="utf-8", errors="replace")
|
||||||
|
except OSError:
|
||||||
|
raise click.UsageError(
|
||||||
|
f"Could not inspect dependency file for embedded credentials: {path}"
|
||||||
|
) from None
|
||||||
|
_validate_git_http_url_userinfo([contents], source=path)
|
||||||
|
|
||||||
|
|
||||||
|
def _validate_local_dependency_files(config_path: pathlib.Path, config: Config) -> None:
|
||||||
|
"""Validate dependency files copied into a non-uv Python image."""
|
||||||
|
paths: list[pathlib.Path] = []
|
||||||
|
for dependency in config["dependencies"]:
|
||||||
|
if not isinstance(dependency, str) or not dependency.startswith("."):
|
||||||
|
continue
|
||||||
|
root = (config_path.parent / dependency).resolve()
|
||||||
|
paths.extend(
|
||||||
|
root / name
|
||||||
|
for name in ("requirements.txt", "pyproject.toml", "setup.py", "setup.cfg")
|
||||||
|
)
|
||||||
|
_validate_git_http_url_userinfo_files(paths)
|
||||||
|
|
||||||
|
|
||||||
MIN_PYTHON_VERSION = "3.11"
|
MIN_PYTHON_VERSION = "3.11"
|
||||||
DEFAULT_PYTHON_VERSION = "3.11"
|
DEFAULT_PYTHON_VERSION = "3.11"
|
||||||
|
|
||||||
@@ -320,7 +381,9 @@ def _get_source_kind(config: Config) -> str | None:
|
|||||||
return kind if isinstance(kind, str) else None
|
return kind if isinstance(kind, str) else None
|
||||||
|
|
||||||
|
|
||||||
def validate_config(config: Config) -> Config:
|
def validate_config(
|
||||||
|
config: Config, *, source_path: pathlib.Path | None = None
|
||||||
|
) -> Config:
|
||||||
"""Validate a configuration dictionary."""
|
"""Validate a configuration dictionary."""
|
||||||
|
|
||||||
graphs = config.get("graphs", {})
|
graphs = config.get("graphs", {})
|
||||||
@@ -415,6 +478,15 @@ def validate_config(config: Config) -> Config:
|
|||||||
' "source": {"kind": "uv", "root": ".."}'
|
' "source": {"kind": "uv", "root": ".."}'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_validate_git_http_url_userinfo(
|
||||||
|
(
|
||||||
|
dependency
|
||||||
|
for dependency in config["dependencies"]
|
||||||
|
if isinstance(dependency, str)
|
||||||
|
),
|
||||||
|
source=source_path,
|
||||||
|
)
|
||||||
|
|
||||||
source = config.get("source")
|
source = config.get("source")
|
||||||
source_kind = _get_source_kind(config)
|
source_kind = _get_source_kind(config)
|
||||||
if source is not None and not isinstance(source, dict):
|
if source is not None and not isinstance(source, dict):
|
||||||
@@ -609,7 +681,7 @@ def validate_config_file(config_path: pathlib.Path) -> Config:
|
|||||||
"""Load and validate a configuration file."""
|
"""Load and validate a configuration file."""
|
||||||
with open(config_path) as f:
|
with open(config_path) as f:
|
||||||
config = json.load(f)
|
config = json.load(f)
|
||||||
validated = validate_config(config)
|
validated = validate_config(config, source_path=config_path.resolve())
|
||||||
# Enforce the package.json doesn't enforce an
|
# Enforce the package.json doesn't enforce an
|
||||||
# incompatible Node.js version
|
# incompatible Node.js version
|
||||||
if validated.get("node_version"):
|
if validated.get("node_version"):
|
||||||
@@ -1280,6 +1352,7 @@ def python_config_to_docker(
|
|||||||
api_version=api_version,
|
api_version=api_version,
|
||||||
build_tools_to_uninstall=build_tools_to_uninstall,
|
build_tools_to_uninstall=build_tools_to_uninstall,
|
||||||
)
|
)
|
||||||
|
_validate_local_dependency_files(config_path, config)
|
||||||
if pip_installer == "auto":
|
if pip_installer == "auto":
|
||||||
if _image_supports_uv(base_image):
|
if _image_supports_uv(base_image):
|
||||||
pip_installer = "uv"
|
pip_installer = "uv"
|
||||||
@@ -1490,7 +1563,18 @@ def node_config_to_docker(
|
|||||||
) -> tuple[str, dict[str, str]]:
|
) -> tuple[str, dict[str, str]]:
|
||||||
# Calculate paths for monorepo support
|
# Calculate paths for monorepo support
|
||||||
install_root = (
|
install_root = (
|
||||||
pathlib.Path(build_context).resolve() if build_context else config_path.parent
|
pathlib.Path(build_context).resolve()
|
||||||
|
if build_context
|
||||||
|
else config_path.parent.resolve()
|
||||||
|
)
|
||||||
|
config_root = config_path.parent.resolve()
|
||||||
|
dependency_roots = (
|
||||||
|
(install_root, config_root) if install_root != config_root else (install_root,)
|
||||||
|
)
|
||||||
|
_validate_git_http_url_userinfo_files(
|
||||||
|
root / name
|
||||||
|
for root in dependency_roots
|
||||||
|
for name in ("package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml")
|
||||||
)
|
)
|
||||||
install_cmd = install_command or _get_node_pm_install_cmd(install_root)
|
install_cmd = install_command or _get_node_pm_install_cmd(install_root)
|
||||||
if build_context:
|
if build_context:
|
||||||
|
|||||||
+940
-340
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,18 @@
|
|||||||
import asyncio
|
import asyncio
|
||||||
import signal
|
import signal
|
||||||
import sys
|
import sys
|
||||||
from collections.abc import Callable
|
from collections.abc import Callable, Coroutine
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
from typing import cast
|
from typing import Any, Protocol, TypeVar, cast
|
||||||
|
|
||||||
import click.exceptions
|
import click.exceptions
|
||||||
|
|
||||||
|
_T = TypeVar("_T")
|
||||||
|
|
||||||
|
|
||||||
|
class CommandRunner(Protocol):
|
||||||
|
def run(self, coro: Coroutine[Any, Any, _T]) -> _T: ...
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
@contextmanager
|
||||||
def Runner():
|
def Runner():
|
||||||
|
|||||||
@@ -2,18 +2,125 @@
|
|||||||
|
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from typing import Any
|
from dataclasses import dataclass
|
||||||
|
from typing import Any, Literal
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import click
|
import click
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
|
CLOUD_CONTROL_PLANE_URL = "https://api.host.langchain.com"
|
||||||
|
CLOUD_DASHBOARD_URL = "https://smith.langchain.com"
|
||||||
|
CLOUD_DOMAIN = "langchain.com"
|
||||||
|
CLOUD_API_HOST = "api.smith.langchain.com"
|
||||||
|
CLOUD_CONTROL_PLANE_HOST = "api.host.langchain.com"
|
||||||
|
CLOUD_DASHBOARD_HOST = "smith.langchain.com"
|
||||||
|
CONTROL_PLANE_PATH = "/api-host"
|
||||||
|
LANGSMITH_API_PATHS = ("/api/v1", "/api")
|
||||||
|
LOCAL_HOSTNAMES = ("localhost", "127.0.0.1")
|
||||||
|
MAX_PAGE_SIZE = 100
|
||||||
|
SourceName = Literal["internal_docker", "internal_source", "external_docker"]
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ControlPlaneEndpoints:
|
||||||
|
control_plane_url: str
|
||||||
|
dashboard_url: str
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def resolve(
|
||||||
|
cls, host_url: str | None, langsmith_endpoint: str | None
|
||||||
|
) -> ControlPlaneEndpoints:
|
||||||
|
if host_url:
|
||||||
|
return cls.from_control_plane_url(host_url)
|
||||||
|
if langsmith_endpoint:
|
||||||
|
return cls.from_langsmith_endpoint(langsmith_endpoint)
|
||||||
|
return cls(CLOUD_CONTROL_PLANE_URL, CLOUD_DASHBOARD_URL)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_cloud(self) -> bool:
|
||||||
|
hostname = urlparse(self.control_plane_url).hostname or ""
|
||||||
|
return hostname == CLOUD_CONTROL_PLANE_HOST or hostname.endswith(
|
||||||
|
f".{CLOUD_CONTROL_PLANE_HOST}"
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_control_plane_url(cls, url: str) -> ControlPlaneEndpoints:
|
||||||
|
control_plane_url = url.rstrip("/")
|
||||||
|
hostname = urlparse(control_plane_url).hostname or ""
|
||||||
|
if control_plane_url.endswith(CONTROL_PLANE_PATH):
|
||||||
|
return cls(control_plane_url, control_plane_url[: -len(CONTROL_PLANE_PATH)])
|
||||||
|
if hostname in LOCAL_HOSTNAMES:
|
||||||
|
return cls(control_plane_url, control_plane_url)
|
||||||
|
return cls(control_plane_url, _cloud_dashboard_for(hostname))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_langsmith_endpoint(cls, endpoint: str) -> ControlPlaneEndpoints:
|
||||||
|
parsed = urlparse(endpoint.rstrip("/"))
|
||||||
|
hostname = parsed.hostname or ""
|
||||||
|
if _is_cloud_host(hostname):
|
||||||
|
return cls.from_control_plane_url(
|
||||||
|
f"https://{_cloud_control_plane_host_for(hostname)}"
|
||||||
|
)
|
||||||
|
root = f"{parsed.scheme}://{parsed.netloc}{_without_api_path(parsed.path)}"
|
||||||
|
return cls(f"{root}{CONTROL_PLANE_PATH}", root)
|
||||||
|
|
||||||
|
|
||||||
|
def _is_cloud_host(hostname: str) -> bool:
|
||||||
|
return hostname == CLOUD_DOMAIN or hostname.endswith(f".{CLOUD_DOMAIN}")
|
||||||
|
|
||||||
|
|
||||||
|
def _cloud_control_plane_host_for(langsmith_api_host: str) -> str:
|
||||||
|
if langsmith_api_host.endswith(f".{CLOUD_API_HOST}"):
|
||||||
|
region = langsmith_api_host[: -len(CLOUD_API_HOST)]
|
||||||
|
return f"{region}{CLOUD_CONTROL_PLANE_HOST}"
|
||||||
|
return CLOUD_CONTROL_PLANE_HOST
|
||||||
|
|
||||||
|
|
||||||
|
def _cloud_dashboard_for(control_plane_host: str) -> str:
|
||||||
|
if control_plane_host.endswith(f".{CLOUD_CONTROL_PLANE_HOST}"):
|
||||||
|
region = control_plane_host[: -len(CLOUD_CONTROL_PLANE_HOST) - 1]
|
||||||
|
return f"https://{region}.{CLOUD_DASHBOARD_HOST}"
|
||||||
|
return CLOUD_DASHBOARD_URL
|
||||||
|
|
||||||
|
|
||||||
|
def _without_api_path(path: str) -> str:
|
||||||
|
for api_path in LANGSMITH_API_PATHS:
|
||||||
|
if path.endswith(api_path):
|
||||||
|
return path[: -len(api_path)]
|
||||||
|
return path
|
||||||
|
|
||||||
|
|
||||||
|
def _resources(payload: object) -> list[dict[str, Any]]:
|
||||||
|
if not isinstance(payload, dict):
|
||||||
|
return []
|
||||||
|
resources = payload.get("resources")
|
||||||
|
if not isinstance(resources, list):
|
||||||
|
return []
|
||||||
|
return [item for item in resources if isinstance(item, dict)]
|
||||||
|
|
||||||
|
|
||||||
class HostBackendError(click.ClickException):
|
class HostBackendError(click.ClickException):
|
||||||
"""Raised when the host backend returns an error response."""
|
"""Raised when the host backend returns an error response."""
|
||||||
|
|
||||||
def __init__(self, message: str, status_code: int | None = None):
|
def __init__(
|
||||||
|
self,
|
||||||
|
message: str,
|
||||||
|
status_code: int | None = None,
|
||||||
|
detail: str | None = None,
|
||||||
|
):
|
||||||
super().__init__(message)
|
super().__init__(message)
|
||||||
self.status_code = status_code
|
self.status_code = status_code
|
||||||
|
self.detail = detail
|
||||||
|
|
||||||
|
|
||||||
|
def _error_detail(response: httpx.Response) -> str | None:
|
||||||
|
try:
|
||||||
|
body = response.json()
|
||||||
|
except ValueError:
|
||||||
|
return None
|
||||||
|
detail = body.get("detail") if isinstance(body, dict) else None
|
||||||
|
return detail if isinstance(detail, str) else None
|
||||||
|
|
||||||
|
|
||||||
class HostBackendClient:
|
class HostBackendClient:
|
||||||
@@ -24,24 +131,37 @@ class HostBackendClient:
|
|||||||
base_url: str,
|
base_url: str,
|
||||||
api_key: str,
|
api_key: str,
|
||||||
tenant_id: str | None = None,
|
tenant_id: str | None = None,
|
||||||
|
*,
|
||||||
|
transport: httpx.BaseTransport | None = None,
|
||||||
):
|
):
|
||||||
if not base_url:
|
if not base_url:
|
||||||
raise click.UsageError("Host backend URL is required")
|
raise click.UsageError("Host backend URL is required")
|
||||||
transport = httpx.HTTPTransport(retries=3)
|
|
||||||
headers: dict[str, str] = {
|
headers: dict[str, str] = {
|
||||||
"X-Api-Key": api_key,
|
"X-Api-Key": api_key,
|
||||||
"Accept": "application/json",
|
"Accept": "application/json",
|
||||||
}
|
}
|
||||||
if tenant_id:
|
if tenant_id:
|
||||||
headers["X-Tenant-ID"] = tenant_id
|
headers["X-Tenant-ID"] = tenant_id
|
||||||
self._base_url = base_url.rstrip("/")
|
self._endpoints = ControlPlaneEndpoints.from_control_plane_url(base_url)
|
||||||
|
self._base_url = self._endpoints.control_plane_url
|
||||||
self._client = httpx.Client(
|
self._client = httpx.Client(
|
||||||
base_url=self._base_url,
|
base_url=self._base_url,
|
||||||
headers=headers,
|
headers=headers,
|
||||||
transport=transport,
|
transport=transport or httpx.HTTPTransport(retries=3),
|
||||||
timeout=30,
|
timeout=30,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def base_url(self) -> str:
|
||||||
|
return self._base_url
|
||||||
|
|
||||||
|
@property
|
||||||
|
def endpoints(self) -> ControlPlaneEndpoints:
|
||||||
|
return self._endpoints
|
||||||
|
|
||||||
|
def set_tenant(self, tenant_id: str) -> None:
|
||||||
|
self._client.headers["X-Tenant-ID"] = tenant_id
|
||||||
|
|
||||||
def _request(
|
def _request(
|
||||||
self,
|
self,
|
||||||
method: str,
|
method: str,
|
||||||
@@ -53,10 +173,12 @@ class HostBackendClient:
|
|||||||
resp = self._client.request(method, path, json=payload, params=params)
|
resp = self._client.request(method, path, json=payload, params=params)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
except httpx.HTTPStatusError as err:
|
except httpx.HTTPStatusError as err:
|
||||||
detail = err.response.text or str(err.response.status_code)
|
detail = _error_detail(err.response)
|
||||||
|
reason = detail or err.response.text or str(err.response.status_code)
|
||||||
raise HostBackendError(
|
raise HostBackendError(
|
||||||
f"{method} {path} failed with status {err.response.status_code}: {detail}",
|
f"{method} {path} failed with status {err.response.status_code}: {reason}",
|
||||||
status_code=err.response.status_code,
|
status_code=err.response.status_code,
|
||||||
|
detail=detail,
|
||||||
) from None
|
) from None
|
||||||
except httpx.TransportError as err:
|
except httpx.TransportError as err:
|
||||||
raise HostBackendError(str(err)) from None
|
raise HostBackendError(str(err)) from None
|
||||||
@@ -72,30 +194,52 @@ class HostBackendClient:
|
|||||||
|
|
||||||
def create_deployment(
|
def create_deployment(
|
||||||
self,
|
self,
|
||||||
name: str,
|
*,
|
||||||
deployment_type: str,
|
name: str | None,
|
||||||
source: str,
|
source: SourceName,
|
||||||
config_path: str | None = None,
|
source_config: dict[str, object],
|
||||||
|
source_revision_config: dict[str, object],
|
||||||
secrets: list[dict[str, str]] | None = None,
|
secrets: list[dict[str, str]] | None = None,
|
||||||
|
agent: dict[str, str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
"""Create a deployment."""
|
|
||||||
payload: dict[str, Any] = {
|
payload: dict[str, Any] = {
|
||||||
"name": name,
|
|
||||||
"source": source,
|
"source": source,
|
||||||
"source_config": {"deployment_type": deployment_type},
|
"source_config": source_config,
|
||||||
"source_revision_config": {},
|
"source_revision_config": source_revision_config,
|
||||||
}
|
}
|
||||||
if source == "internal_source" and config_path:
|
if agent is not None:
|
||||||
payload["source_revision_config"]["langgraph_config_path"] = config_path
|
payload["agent"] = agent
|
||||||
|
else:
|
||||||
|
payload["name"] = name
|
||||||
if secrets is not None:
|
if secrets is not None:
|
||||||
payload["secrets"] = secrets
|
payload["secrets"] = secrets
|
||||||
return self._request("POST", "/v2/deployments", payload)
|
return self._request("POST", "/v2/deployments", payload)
|
||||||
|
|
||||||
def list_deployments(self, name_contains: str = "") -> dict[str, Any]:
|
def list_deployments(
|
||||||
return self._request(
|
self,
|
||||||
"GET",
|
*,
|
||||||
"/v2/deployments",
|
name: str | None = None,
|
||||||
params={"name_contains": name_contains},
|
name_contains: str | None = None,
|
||||||
|
limit: int | None = None,
|
||||||
|
agent_id: str | None = None,
|
||||||
|
agent_environment: str | None = None,
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
given = (
|
||||||
|
("name", name),
|
||||||
|
("name_contains", name_contains),
|
||||||
|
("limit", limit),
|
||||||
|
("agent_id", agent_id),
|
||||||
|
("agent_environment", agent_environment),
|
||||||
|
)
|
||||||
|
params = {key: value for key, value in given if value is not None}
|
||||||
|
return _resources(self._request("GET", "/v2/deployments", params=params))
|
||||||
|
|
||||||
|
def get_listener(self, listener_id: str) -> dict[str, Any]:
|
||||||
|
return self._request("GET", f"/v2/listeners/{listener_id}")
|
||||||
|
|
||||||
|
def list_listeners(self) -> list[dict[str, Any]]:
|
||||||
|
return _resources(
|
||||||
|
self._request("GET", "/v2/listeners", params={"limit": MAX_PAGE_SIZE})
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_deployment(self, deployment_id: str) -> dict[str, Any]:
|
def get_deployment(self, deployment_id: str) -> dict[str, Any]:
|
||||||
@@ -121,22 +265,21 @@ class HostBackendClient:
|
|||||||
self,
|
self,
|
||||||
deployment_id: str,
|
deployment_id: str,
|
||||||
image_uri: str,
|
image_uri: str,
|
||||||
|
*,
|
||||||
|
revision_source: SourceName | None,
|
||||||
secrets: list[dict[str, str]] | None = None,
|
secrets: list[dict[str, str]] | None = None,
|
||||||
tracked_packages: list[str] | None = None,
|
tracked_packages: list[str] | None = None,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
payload: dict[str, Any] = {
|
payload: dict[str, Any] = {
|
||||||
"revision_source": "internal_docker",
|
|
||||||
"source_revision_config": {"image_uri": image_uri},
|
"source_revision_config": {"image_uri": image_uri},
|
||||||
}
|
}
|
||||||
|
if revision_source is not None:
|
||||||
|
payload["revision_source"] = revision_source
|
||||||
if tracked_packages:
|
if tracked_packages:
|
||||||
payload["tracked_packages"] = tracked_packages
|
payload["tracked_packages"] = tracked_packages
|
||||||
if secrets is not None:
|
if secrets is not None:
|
||||||
payload["secrets"] = secrets
|
payload["secrets"] = secrets
|
||||||
return self._request(
|
return self._request("PATCH", f"/v2/deployments/{deployment_id}", payload)
|
||||||
"PATCH",
|
|
||||||
f"/v2/deployments/{deployment_id}",
|
|
||||||
payload,
|
|
||||||
)
|
|
||||||
|
|
||||||
def update_deployment_internal_source(
|
def update_deployment_internal_source(
|
||||||
self,
|
self,
|
||||||
@@ -171,10 +314,15 @@ class HostBackendClient:
|
|||||||
payload["secrets"] = secrets
|
payload["secrets"] = secrets
|
||||||
return self._request("PATCH", f"/v2/deployments/{deployment_id}", payload)
|
return self._request("PATCH", f"/v2/deployments/{deployment_id}", payload)
|
||||||
|
|
||||||
def list_revisions(self, deployment_id: str, limit: int = 1) -> dict[str, Any]:
|
def list_revisions(
|
||||||
return self._request(
|
self, deployment_id: str, limit: int = 1
|
||||||
|
) -> list[dict[str, Any]]:
|
||||||
|
return _resources(
|
||||||
|
self._request(
|
||||||
"GET",
|
"GET",
|
||||||
f"/v2/deployments/{deployment_id}/revisions?limit={limit}",
|
f"/v2/deployments/{deployment_id}/revisions",
|
||||||
|
params={"limit": limit},
|
||||||
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_revision(self, deployment_id: str, revision_id: str) -> dict[str, Any]:
|
def get_revision(self, deployment_id: str, revision_id: str) -> dict[str, Any]:
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
from dataclasses import dataclass, replace
|
||||||
|
|
||||||
|
DIGEST_SEPARATOR = "@sha256:"
|
||||||
|
DIGEST_MARKER = "@"
|
||||||
|
TAG_SEPARATOR = ":"
|
||||||
|
PATH_SEPARATOR = "/"
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(frozen=True, slots=True)
|
||||||
|
class ImageReference:
|
||||||
|
repository: str
|
||||||
|
tag: str | None = None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def parse(cls, reference: str) -> ImageReference:
|
||||||
|
if DIGEST_MARKER in reference:
|
||||||
|
raise ValueError(f"{reference!r} carries a digest and cannot be tagged")
|
||||||
|
path_start = reference.rfind(PATH_SEPARATOR) + 1
|
||||||
|
name, separator, tag = reference[path_start:].partition(TAG_SEPARATOR)
|
||||||
|
if not separator:
|
||||||
|
return cls(reference)
|
||||||
|
return cls(reference[:path_start] + name, tag)
|
||||||
|
|
||||||
|
def with_tag(self, tag: str) -> ImageReference:
|
||||||
|
return replace(self, tag=tag)
|
||||||
|
|
||||||
|
def matches_digest(self, repo_digest: str) -> bool:
|
||||||
|
return repo_digest.startswith(f"{self.repository}{DIGEST_SEPARATOR}")
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
if self.tag is None:
|
||||||
|
return self.repository
|
||||||
|
return f"{self.repository}{TAG_SEPARATOR}{self.tag}"
|
||||||
@@ -650,7 +650,8 @@ class Config(TypedDict, total=False):
|
|||||||
|
|
||||||
pip_config_file: str | None
|
pip_config_file: str | None
|
||||||
"""Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling
|
"""Optional. Path to a pip config file (e.g., "/etc/pip.conf" or "pip.ini") for controlling
|
||||||
package installation (custom indices, credentials, etc.).
|
package installation (custom indices, timeouts, etc.). The file is copied into the
|
||||||
|
generated image, so it must not contain credentials or other secrets.
|
||||||
|
|
||||||
Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.
|
Only relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.
|
||||||
"""
|
"""
|
||||||
@@ -689,6 +690,9 @@ class Config(TypedDict, total=False):
|
|||||||
- "." or "./src" if you have a local Python package
|
- "." or "./src" if you have a local Python package
|
||||||
- str (aka "anthropic") for a PyPI package
|
- str (aka "anthropic") for a PyPI package
|
||||||
- "git+https://github.com/org/repo.git@main" for a Git-based package
|
- "git+https://github.com/org/repo.git@main" for a Git-based package
|
||||||
|
Git HTTP URLs must not contain userinfo such as a username or token. For private
|
||||||
|
dependencies, provide short-lived credentials through the build environment's
|
||||||
|
secret-backed Git credential helper.
|
||||||
Defaults to an empty list, meaning no additional packages installed beyond your base environment.
|
Defaults to an empty list, meaning no additional packages installed beyond your base environment.
|
||||||
|
|
||||||
This field is not supported when `source.kind` is `uv`.
|
This field is not supported when `source.kind` is `uv`.
|
||||||
|
|||||||
@@ -880,6 +880,7 @@ def python_config_to_docker_uv_lock(
|
|||||||
_get_node_pm_install_cmd,
|
_get_node_pm_install_cmd,
|
||||||
_get_pip_cleanup_lines,
|
_get_pip_cleanup_lines,
|
||||||
_image_supports_uv,
|
_image_supports_uv,
|
||||||
|
_validate_git_http_url_userinfo_files,
|
||||||
docker_tag,
|
docker_tag,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -890,11 +891,20 @@ def python_config_to_docker_uv_lock(
|
|||||||
)
|
)
|
||||||
|
|
||||||
config_root = config_path.parent.resolve()
|
config_root = config_path.parent.resolve()
|
||||||
|
source_root = config["source"].get("root", ".")
|
||||||
|
project_root = (config_root / source_root).resolve()
|
||||||
|
_validate_git_http_url_userinfo_files(
|
||||||
|
[project_root / "pyproject.toml", project_root / "uv.lock"]
|
||||||
|
)
|
||||||
|
|
||||||
install_cmd = "uv pip install --system"
|
install_cmd = "uv pip install --system"
|
||||||
_, global_reqs_pip_install, pip_config_file_str = _build_python_install_commands(
|
_, global_reqs_pip_install, pip_config_file_str = _build_python_install_commands(
|
||||||
config, install_cmd
|
config, install_cmd
|
||||||
)
|
)
|
||||||
plan = _plan_uv_lock_workspace(config_path, config)
|
plan = _plan_uv_lock_workspace(config_path, config)
|
||||||
|
_validate_git_http_url_userinfo_files(
|
||||||
|
package.pyproject_path for package in plan.install_order
|
||||||
|
)
|
||||||
|
|
||||||
_update_uv_lock_graph_paths(config_path, config, plan)
|
_update_uv_lock_graph_paths(config_path, config, plan)
|
||||||
for section, key in [
|
for section, key in [
|
||||||
@@ -970,6 +980,22 @@ def python_config_to_docker_uv_lock(
|
|||||||
f"{uv_export_project_dir}/uv.lock",
|
f"{uv_export_project_dir}/uv.lock",
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
for package_root in sorted(
|
||||||
|
plan.all_workspace_roots,
|
||||||
|
key=lambda root: root.as_posix(),
|
||||||
|
):
|
||||||
|
if package_root == plan.project_root:
|
||||||
|
continue
|
||||||
|
package_relative_path = pathlib.PurePosixPath(
|
||||||
|
package_root.relative_to(plan.project_root).as_posix()
|
||||||
|
)
|
||||||
|
package_pyproject_path = package_relative_path / "pyproject.toml"
|
||||||
|
docker_plan.add_raw(
|
||||||
|
copy_from_project_root(
|
||||||
|
package_pyproject_path,
|
||||||
|
f"{uv_export_project_dir}/{package_pyproject_path.as_posix()}",
|
||||||
|
)
|
||||||
|
)
|
||||||
docker_plan.add_instruction("WORKDIR", uv_export_project_dir)
|
docker_plan.add_instruction("WORKDIR", uv_export_project_dir)
|
||||||
docker_plan.add_instruction(
|
docker_plan.add_instruction(
|
||||||
"RUN",
|
"RUN",
|
||||||
|
|||||||
@@ -72,9 +72,15 @@ lint.select = [
|
|||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
"B", # flake8-bugbear
|
"B", # flake8-bugbear
|
||||||
"I", # isort
|
"I", # isort
|
||||||
|
"PLC0415", # import-outside-top-level
|
||||||
|
"RUF100", # unused noqa directive
|
||||||
"UP", # pyupgrade
|
"UP", # pyupgrade
|
||||||
]
|
]
|
||||||
lint.ignore = ["E501", "B008"]
|
lint.ignore = ["E501", "B008"]
|
||||||
|
# PLC0415 (import-outside-top-level) is enforced in tests only. Library code
|
||||||
|
# still has deferred imports that have not been reviewed, so it stays exempt
|
||||||
|
# for now.
|
||||||
|
lint.per-file-ignores = { "langgraph_cli/**" = ["PLC0415"], "generate_schema.py" = ["PLC0415"] }
|
||||||
target-version = "py310"
|
target-version = "py310"
|
||||||
|
|
||||||
[tool.ty.rules]
|
[tool.ty.rules]
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, timeouts, etc.). The file is copied into the\ngenerated image, so it must not contain credentials or other secrets.\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
||||||
},
|
},
|
||||||
"_INTERNAL_docker_tag": {
|
"_INTERNAL_docker_tag": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, timeouts, etc.). The file is copied into the\ngenerated image, so it must not contain credentials or other secrets.\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
||||||
},
|
},
|
||||||
"_INTERNAL_docker_tag": {
|
"_INTERNAL_docker_tag": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
|||||||
@@ -28,7 +28,7 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, timeouts, etc.). The file is copied into the\ngenerated image, so it must not contain credentials or other secrets.\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
||||||
},
|
},
|
||||||
"_INTERNAL_docker_tag": {
|
"_INTERNAL_docker_tag": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
@@ -270,7 +270,7 @@
|
|||||||
"type": "null"
|
"type": "null"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, credentials, etc.).\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
"description": "Optional. Path to a pip config file (e.g., \"/etc/pip.conf\" or \"pip.ini\") for controlling\npackage installation (custom indices, timeouts, etc.). The file is copied into the\ngenerated image, so it must not contain credentials or other secrets.\n\nOnly relevant if Python dependencies are installed via pip. If omitted, default pip settings are used.\n"
|
||||||
},
|
},
|
||||||
"_INTERNAL_docker_tag": {
|
"_INTERNAL_docker_tag": {
|
||||||
"anyOf": [
|
"anyOf": [
|
||||||
|
|||||||
@@ -320,6 +320,31 @@ def test_top_level_help_truncates_command_descriptions_to_single_line() -> None:
|
|||||||
assert "[Beta] List LangSmith Deployments." in deploy_list_line
|
assert "[Beta] List LangSmith Deployments." in deploy_list_line
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_missing_config_shows_actionable_error(tmp_path, monkeypatch) -> None:
|
||||||
|
runner = CliRunner()
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
|
||||||
|
result = runner.invoke(cli, ["deploy"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
assert "We couldn't find a langgraph.json file." in result.output
|
||||||
|
assert "Run `langgraph deploy` from the root" in result.output
|
||||||
|
assert "https://docs.langchain.com/langsmith/deployment-quickstart" in result.output
|
||||||
|
assert "Traceback" not in result.output
|
||||||
|
|
||||||
|
|
||||||
|
def test_deploy_missing_config_emits_json_error(tmp_path, monkeypatch) -> None:
|
||||||
|
runner = CliRunner()
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
|
||||||
|
result = runner.invoke(cli, ["deploy", "--json"])
|
||||||
|
|
||||||
|
assert result.exit_code == 1
|
||||||
|
events = [json.loads(line) for line in result.output.splitlines()]
|
||||||
|
assert events[-1]["event"] == "error"
|
||||||
|
assert "We couldn't find a langgraph.json file." in events[-1]["message"]
|
||||||
|
|
||||||
|
|
||||||
def test_dev_command_requires_ssl_certfile_and_keyfile_together(tmp_path) -> None:
|
def test_dev_command_requires_ssl_certfile_and_keyfile_together(tmp_path) -> None:
|
||||||
config_path = tmp_path / "langgraph.json"
|
config_path = tmp_path / "langgraph.json"
|
||||||
config_path.write_text(
|
config_path.write_text(
|
||||||
@@ -357,8 +382,7 @@ def test_deploy_list_command(monkeypatch) -> None:
|
|||||||
|
|
||||||
def list_deployments(self, name_contains: str = ""):
|
def list_deployments(self, name_contains: str = ""):
|
||||||
captured["name_contains"] = name_contains
|
captured["name_contains"] = name_contains
|
||||||
return {
|
return [
|
||||||
"resources": [
|
|
||||||
{
|
{
|
||||||
"id": "dep-123",
|
"id": "dep-123",
|
||||||
"name": "alpha",
|
"name": "alpha",
|
||||||
@@ -370,7 +394,6 @@ def test_deploy_list_command(monkeypatch) -> None:
|
|||||||
"source_config": {"custom_url": "https://beta.example.com"},
|
"source_config": {"custom_url": "https://beta.example.com"},
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
||||||
|
|
||||||
@@ -410,7 +433,7 @@ def test_deploy_list_command_no_results(monkeypatch) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def list_deployments(self, name_contains: str = ""):
|
def list_deployments(self, name_contains: str = ""):
|
||||||
return {"resources": []}
|
return []
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
||||||
|
|
||||||
@@ -443,8 +466,7 @@ def test_deploy_revisions_list_command(monkeypatch) -> None:
|
|||||||
def list_revisions(self, deployment_id: str, limit: int = 1):
|
def list_revisions(self, deployment_id: str, limit: int = 1):
|
||||||
captured["deployment_id"] = deployment_id
|
captured["deployment_id"] = deployment_id
|
||||||
captured["limit"] = str(limit)
|
captured["limit"] = str(limit)
|
||||||
return {
|
return [
|
||||||
"resources": [
|
|
||||||
{
|
{
|
||||||
"id": "rev-123",
|
"id": "rev-123",
|
||||||
"status": "CREATING",
|
"status": "CREATING",
|
||||||
@@ -456,7 +478,6 @@ def test_deploy_revisions_list_command(monkeypatch) -> None:
|
|||||||
"created_at": "2023-11-08T10:00:00Z",
|
"created_at": "2023-11-08T10:00:00Z",
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
}
|
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
||||||
|
|
||||||
@@ -497,7 +518,7 @@ def test_deploy_revisions_list_command_no_results(monkeypatch) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
def list_revisions(self, deployment_id: str, limit: int = 1):
|
def list_revisions(self, deployment_id: str, limit: int = 1):
|
||||||
return {"resources": []}
|
return []
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
||||||
|
|
||||||
@@ -530,7 +551,7 @@ def test_deploy_revisions_list_command_with_explicit_limit(monkeypatch) -> None:
|
|||||||
def list_revisions(self, deployment_id: str, limit: int = 1):
|
def list_revisions(self, deployment_id: str, limit: int = 1):
|
||||||
captured["deployment_id"] = deployment_id
|
captured["deployment_id"] = deployment_id
|
||||||
captured["limit"] = str(limit)
|
captured["limit"] = str(limit)
|
||||||
return {"resources": []}
|
return []
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
monkeypatch.setattr(deploy_module, "HostBackendClient", FakeClient)
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -12,5 +12,5 @@ def disable_analytics_env() -> None:
|
|||||||
if "LANGGRAPH_CLI_NO_ANALYTICS" in os.environ:
|
if "LANGGRAPH_CLI_NO_ANALYTICS" in os.environ:
|
||||||
print("⚠️ LANGGRAPH_CLI_NO_ANALYTICS is set. Overriding it for the test.")
|
print("⚠️ LANGGRAPH_CLI_NO_ANALYTICS is set. Overriding it for the test.")
|
||||||
|
|
||||||
with patch.dict(os.environ, {"LANGGRAPH_CLI_NO_ANALYTICS": "0"}):
|
with patch.dict(os.environ, {"LANGGRAPH_CLI_NO_ANALYTICS": "1"}):
|
||||||
yield
|
yield
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ from langgraph_cli.archive import (
|
|||||||
_tar_filter,
|
_tar_filter,
|
||||||
create_archive,
|
create_archive,
|
||||||
)
|
)
|
||||||
|
from langgraph_cli.config import LocalDeps
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# _tar_filter
|
# _tar_filter
|
||||||
@@ -198,7 +199,6 @@ class TestCreateArchive:
|
|||||||
|
|
||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
def test_yields_archive_with_config(self, mock_deps, tmp_path):
|
def test_yields_archive_with_config(self, mock_deps, tmp_path):
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
config_file = self._make_project(tmp_path)
|
config_file = self._make_project(tmp_path)
|
||||||
mock_deps.return_value = LocalDeps(
|
mock_deps.return_value = LocalDeps(
|
||||||
@@ -218,7 +218,6 @@ class TestCreateArchive:
|
|||||||
|
|
||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
def test_excludes_pycache(self, mock_deps, tmp_path):
|
def test_excludes_pycache(self, mock_deps, tmp_path):
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
config_file = self._make_project(tmp_path)
|
config_file = self._make_project(tmp_path)
|
||||||
mock_deps.return_value = LocalDeps(
|
mock_deps.return_value = LocalDeps(
|
||||||
@@ -232,7 +231,6 @@ class TestCreateArchive:
|
|||||||
|
|
||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
def test_cleans_up_tmp_dir_on_normal_exit(self, mock_deps, tmp_path):
|
def test_cleans_up_tmp_dir_on_normal_exit(self, mock_deps, tmp_path):
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
config_file = self._make_project(tmp_path)
|
config_file = self._make_project(tmp_path)
|
||||||
mock_deps.return_value = LocalDeps(
|
mock_deps.return_value = LocalDeps(
|
||||||
@@ -247,7 +245,6 @@ class TestCreateArchive:
|
|||||||
|
|
||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
def test_cleans_up_tmp_dir_on_exception(self, mock_deps, tmp_path):
|
def test_cleans_up_tmp_dir_on_exception(self, mock_deps, tmp_path):
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
config_file = self._make_project(tmp_path)
|
config_file = self._make_project(tmp_path)
|
||||||
mock_deps.return_value = LocalDeps(
|
mock_deps.return_value = LocalDeps(
|
||||||
@@ -264,7 +261,6 @@ class TestCreateArchive:
|
|||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
@patch("langgraph_cli.archive._MAX_SIZE", 10)
|
@patch("langgraph_cli.archive._MAX_SIZE", 10)
|
||||||
def test_raises_on_oversized_archive(self, mock_deps, tmp_path):
|
def test_raises_on_oversized_archive(self, mock_deps, tmp_path):
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
config_file = self._make_project(tmp_path)
|
config_file = self._make_project(tmp_path)
|
||||||
mock_deps.return_value = LocalDeps(
|
mock_deps.return_value = LocalDeps(
|
||||||
@@ -278,7 +274,6 @@ class TestCreateArchive:
|
|||||||
@patch("langgraph_cli.archive._assemble_local_deps")
|
@patch("langgraph_cli.archive._assemble_local_deps")
|
||||||
def test_handles_extra_contexts(self, mock_deps, tmp_path):
|
def test_handles_extra_contexts(self, mock_deps, tmp_path):
|
||||||
"""Monorepo case: project + sibling dependency directory."""
|
"""Monorepo case: project + sibling dependency directory."""
|
||||||
from langgraph_cli.config import LocalDeps
|
|
||||||
|
|
||||||
project = tmp_path / "myproject"
|
project = tmp_path / "myproject"
|
||||||
project.mkdir()
|
project.mkdir()
|
||||||
|
|||||||
@@ -255,6 +255,243 @@ def test_validate_config():
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"dependency",
|
||||||
|
[
|
||||||
|
"git+https://user:secret-token@github.com/org/private.git@main",
|
||||||
|
"private-package @ git+http://token@github.com/org/private.git",
|
||||||
|
"git+HTTPS://user%40example.com:secret%2Ftoken@github.com/org/private.git",
|
||||||
|
"git+https://${GIT_TOKEN}@github.com/org/private.git",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_validate_config_rejects_git_http_url_userinfo(dependency: str):
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
validate_config(
|
||||||
|
{
|
||||||
|
"python_version": "3.11",
|
||||||
|
"dependencies": [dependency],
|
||||||
|
"graphs": {"agent": "./agent.py:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "must not contain credentials or other URL userinfo" in message
|
||||||
|
assert "secret-token" not in message
|
||||||
|
assert "secret%2Ftoken" not in message
|
||||||
|
|
||||||
|
|
||||||
|
def test_validate_config_file_reports_source_for_git_http_url_userinfo(
|
||||||
|
tmp_path: pathlib.Path,
|
||||||
|
):
|
||||||
|
config_path = tmp_path / "langgraph.json"
|
||||||
|
config_path.write_text(
|
||||||
|
json.dumps(
|
||||||
|
{
|
||||||
|
"python_version": "3.11",
|
||||||
|
"dependencies": ["git+https://secret-token@github.com/org/private.git"],
|
||||||
|
"graphs": {"agent": "./agent.py:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
validate_config_file(config_path)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "secret-token" not in message
|
||||||
|
assert f"Found in: {config_path.resolve()}" in message
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"manifest", ["package.json", "package-lock.json", "yarn.lock", "pnpm-lock.yaml"]
|
||||||
|
)
|
||||||
|
def test_config_to_docker_rejects_git_http_url_userinfo_in_node_files(
|
||||||
|
tmp_path: pathlib.Path, manifest: str
|
||||||
|
):
|
||||||
|
config_path = tmp_path / "langgraph.json"
|
||||||
|
config_path.write_text("{}\n")
|
||||||
|
(tmp_path / "agent.js").write_text("export const graph = {};\n")
|
||||||
|
(tmp_path / "package.json").write_text('{"name":"agent"}\n')
|
||||||
|
(tmp_path / manifest).write_text(
|
||||||
|
'"priv": "git+https://user:secret-token@github.com/org/private.git"\n'
|
||||||
|
)
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"node_version": "20",
|
||||||
|
"graphs": {"agent": "./agent.js:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
config_to_docker(
|
||||||
|
config_path,
|
||||||
|
config,
|
||||||
|
base_image="langchain/langgraphjs-api",
|
||||||
|
)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "must not contain credentials or other URL userinfo" in message
|
||||||
|
assert "secret-token" not in message
|
||||||
|
assert f"Found in: {(tmp_path / manifest).resolve()}" in message
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_to_docker_allows_node_git_urls_without_http_userinfo(
|
||||||
|
tmp_path: pathlib.Path,
|
||||||
|
):
|
||||||
|
config_path = tmp_path / "langgraph.json"
|
||||||
|
config_path.write_text("{}\n")
|
||||||
|
(tmp_path / "agent.js").write_text("export const graph = {};\n")
|
||||||
|
(tmp_path / "package.json").write_text(
|
||||||
|
'{"dependencies":{"public":"git+https://github.com/org/public.git"}}\n'
|
||||||
|
)
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"node_version": "20",
|
||||||
|
"graphs": {"agent": "./agent.js:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
docker, _ = config_to_docker(
|
||||||
|
config_path,
|
||||||
|
config,
|
||||||
|
base_image="langchain/langgraphjs-api",
|
||||||
|
)
|
||||||
|
|
||||||
|
assert f"ADD . /deps/{tmp_path.name}" in docker
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_to_docker_rejects_git_http_url_userinfo_in_node_workspace(
|
||||||
|
tmp_path: pathlib.Path,
|
||||||
|
):
|
||||||
|
config_root = tmp_path / "apps" / "agent"
|
||||||
|
config_root.mkdir(parents=True)
|
||||||
|
config_path = config_root / "langgraph.json"
|
||||||
|
config_path.write_text("{}\n")
|
||||||
|
(config_root / "agent.js").write_text("export const graph = {};\n")
|
||||||
|
(config_root / "package.json").write_text(
|
||||||
|
'{"dependencies":{"priv":"git+https://secret-token@github.com/org/private.git"}}\n'
|
||||||
|
)
|
||||||
|
(tmp_path / "package.json").write_text('{"name":"workspace"}\n')
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"node_version": "20",
|
||||||
|
"graphs": {"agent": "./agent.js:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
config_to_docker(
|
||||||
|
config_path,
|
||||||
|
config,
|
||||||
|
base_image="langchain/langgraphjs-api",
|
||||||
|
build_context=str(tmp_path),
|
||||||
|
)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "secret-token" not in message
|
||||||
|
assert f"Found in: {(config_root / 'package.json').resolve()}" in message
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"dependency",
|
||||||
|
[
|
||||||
|
"git+https://github.com/org/public.git@main",
|
||||||
|
"private-package @ git+https://github.com/org/private.git@main",
|
||||||
|
"git+ssh://git@github.com/org/private.git@main",
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_validate_config_allows_git_urls_without_http_userinfo(dependency: str):
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"python_version": "3.11",
|
||||||
|
"dependencies": [dependency],
|
||||||
|
"graphs": {"agent": "./agent.py:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert config["dependencies"] == [dependency]
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_to_docker_rejects_git_http_url_userinfo_in_requirements(
|
||||||
|
tmp_path: pathlib.Path,
|
||||||
|
):
|
||||||
|
config_path = tmp_path / "langgraph.json"
|
||||||
|
config_path.write_text("{}\n")
|
||||||
|
(tmp_path / "agent.py").write_text("graph = object()\n")
|
||||||
|
(tmp_path / "requirements.txt").write_text(
|
||||||
|
"private @ git+https://secret-token@github.com/org/private.git\n"
|
||||||
|
)
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"python_version": "3.11",
|
||||||
|
"dependencies": ["."],
|
||||||
|
"graphs": {"agent": "./agent.py:graph"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
config_to_docker(
|
||||||
|
config_path,
|
||||||
|
config,
|
||||||
|
base_image="langchain/langgraph-api:0.2.47",
|
||||||
|
)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "must not contain credentials or other URL userinfo" in message
|
||||||
|
assert "secret-token" not in message
|
||||||
|
assert f"Found in: {(tmp_path / 'requirements.txt').resolve()}" in message
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("manifest", ["pyproject.toml", "uv.lock"])
|
||||||
|
def test_config_to_docker_rejects_git_http_url_userinfo_in_uv_files(
|
||||||
|
tmp_path: pathlib.Path, manifest: str
|
||||||
|
):
|
||||||
|
config_path = tmp_path / "langgraph.json"
|
||||||
|
config_path.write_text("{}\n")
|
||||||
|
(tmp_path / "src").mkdir()
|
||||||
|
(tmp_path / "src" / "agent.py").write_text("graph = object()\n")
|
||||||
|
pyproject = textwrap.dedent(
|
||||||
|
"""
|
||||||
|
[project]
|
||||||
|
name = "agent"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = ["private"]
|
||||||
|
|
||||||
|
[tool.uv.sources]
|
||||||
|
private = { git = "https://github.com/org/private.git" }
|
||||||
|
"""
|
||||||
|
).strip()
|
||||||
|
uv_lock = "# uv lock file\n"
|
||||||
|
if manifest == "pyproject.toml":
|
||||||
|
pyproject = pyproject.replace(
|
||||||
|
"https://github.com", "https://secret-token@github.com"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
uv_lock += (
|
||||||
|
'source = { git = "https://secret-token@github.com/org/private.git" }\n'
|
||||||
|
)
|
||||||
|
(tmp_path / "pyproject.toml").write_text(pyproject + "\n")
|
||||||
|
(tmp_path / "uv.lock").write_text(uv_lock)
|
||||||
|
config = validate_config(
|
||||||
|
{
|
||||||
|
"python_version": "3.11",
|
||||||
|
"graphs": {"agent": "./src/agent.py:graph"},
|
||||||
|
"source": {"kind": "uv"},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError) as exc_info:
|
||||||
|
config_to_docker(
|
||||||
|
config_path,
|
||||||
|
config,
|
||||||
|
base_image="langchain/langgraph-api:0.2.47",
|
||||||
|
)
|
||||||
|
|
||||||
|
message = str(exc_info.value)
|
||||||
|
assert "must not contain credentials or other URL userinfo" in message
|
||||||
|
assert "secret-token" not in message
|
||||||
|
|
||||||
|
|
||||||
def test_validate_config_image_distro():
|
def test_validate_config_image_distro():
|
||||||
"""Test validation of image_distro field."""
|
"""Test validation of image_distro field."""
|
||||||
# Valid image_distro values should work
|
# Valid image_distro values should work
|
||||||
@@ -1403,6 +1640,19 @@ def test_config_to_docker_uv_lock():
|
|||||||
"COPY --from=uv-workspace-root uv.lock /tmp/uv_export/project/uv.lock"
|
"COPY --from=uv-workspace-root uv.lock /tmp/uv_export/project/uv.lock"
|
||||||
in docker
|
in docker
|
||||||
)
|
)
|
||||||
|
workspace_pyprojects = [
|
||||||
|
"apps/agent/pyproject.toml",
|
||||||
|
"libs/extra/pyproject.toml",
|
||||||
|
"libs/shared/pyproject.toml",
|
||||||
|
]
|
||||||
|
export_instruction = "RUN uv export --package agent"
|
||||||
|
for pyproject_path in workspace_pyprojects:
|
||||||
|
copy_instruction = (
|
||||||
|
"COPY --from=uv-workspace-root "
|
||||||
|
f"{pyproject_path} /tmp/uv_export/project/{pyproject_path}"
|
||||||
|
)
|
||||||
|
assert copy_instruction in docker
|
||||||
|
assert docker.index(copy_instruction) < docker.index(export_instruction)
|
||||||
assert additional_contexts == {"uv-workspace-root": str(project_root.resolve())}
|
assert additional_contexts == {"uv-workspace-root": str(project_root.resolve())}
|
||||||
|
|
||||||
assert (
|
assert (
|
||||||
|
|||||||
@@ -0,0 +1,119 @@
|
|||||||
|
import json
|
||||||
|
from unittest.mock import Mock
|
||||||
|
|
||||||
|
import httpx
|
||||||
|
import pytest
|
||||||
|
from click.testing import CliRunner
|
||||||
|
|
||||||
|
import langgraph_cli.deploy as deploy
|
||||||
|
from langgraph_cli.cli import cli
|
||||||
|
from langgraph_cli.host_backend import HostBackendClient
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def deployment_api(monkeypatch, tmp_path):
|
||||||
|
monkeypatch.chdir(tmp_path)
|
||||||
|
monkeypatch.delenv("LANGSMITH_DEPLOYMENT_NAME", raising=False)
|
||||||
|
monkeypatch.setattr(deploy, "_emitter", None)
|
||||||
|
monkeypatch.setattr(deploy, "_no_input", False)
|
||||||
|
(tmp_path / "langgraph.json").write_text(
|
||||||
|
json.dumps({"dependencies": ["."], "graphs": {"agent": "./agent.py:graph"}})
|
||||||
|
)
|
||||||
|
(tmp_path / ".env").write_text("LANGSMITH_DEPLOYMENT_NAME=legacy\n")
|
||||||
|
requests = []
|
||||||
|
state = {"enabled": True, "resources": []}
|
||||||
|
|
||||||
|
def handler(request):
|
||||||
|
requests.append(request)
|
||||||
|
assert request.url.path == "/v2/deployments"
|
||||||
|
if request.method == "GET":
|
||||||
|
if not state["enabled"] and (
|
||||||
|
"agent_id" in request.url.params
|
||||||
|
or "agent_environment" in request.url.params
|
||||||
|
):
|
||||||
|
return httpx.Response(
|
||||||
|
400, text="Agent filters are not available for this tenant."
|
||||||
|
)
|
||||||
|
return httpx.Response(200, json={"resources": state["resources"]})
|
||||||
|
assert request.method == "POST"
|
||||||
|
return httpx.Response(200, json={"id": "runtime-id", "name": "server-name"})
|
||||||
|
|
||||||
|
client = HostBackendClient("https://api.example.com", "test-key")
|
||||||
|
client._client.close()
|
||||||
|
client._client = httpx.Client(
|
||||||
|
base_url="https://api.example.com",
|
||||||
|
transport=httpx.MockTransport(handler),
|
||||||
|
headers={"X-Api-Key": "test-key"},
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(deploy, "_create_host_backend_client", lambda *a, **kw: client)
|
||||||
|
monkeypatch.setattr(deploy, "find_tracked_packages", lambda *a: [])
|
||||||
|
remote_build = Mock(return_value=deploy.BuildResult())
|
||||||
|
monkeypatch.setattr(deploy, "_run_remote_build", remote_build)
|
||||||
|
monkeypatch.setattr(deploy, "_resolve_build_mode", lambda flag, **kw: (flag, None))
|
||||||
|
yield state, requests, remote_build
|
||||||
|
client._client.close()
|
||||||
|
|
||||||
|
|
||||||
|
AGENT_ARGS = [
|
||||||
|
"deploy",
|
||||||
|
"--agent-id",
|
||||||
|
"customer-support",
|
||||||
|
"--agent-environment",
|
||||||
|
"staging",
|
||||||
|
"--remote",
|
||||||
|
"--no-wait",
|
||||||
|
"--no-input",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_create(deployment_api, tmp_path, monkeypatch):
|
||||||
|
monkeypatch.setenv("LANGSMITH_DEPLOYMENT_NAME", "legacy")
|
||||||
|
_, requests, build = deployment_api
|
||||||
|
result = CliRunner().invoke(cli, AGENT_ARGS)
|
||||||
|
assert result.exit_code == 0, result.output
|
||||||
|
assert dict(requests[0].url.params) == {
|
||||||
|
"agent_id": "customer-support",
|
||||||
|
"agent_environment": "staging",
|
||||||
|
"limit": "100",
|
||||||
|
}
|
||||||
|
payload = json.loads(requests[1].content)
|
||||||
|
assert payload["agent"] == {
|
||||||
|
"agent_id": "customer-support",
|
||||||
|
"environment": "staging",
|
||||||
|
}
|
||||||
|
assert "name" not in payload
|
||||||
|
assert build.call_args.kwargs["deployment_id"] == "runtime-id"
|
||||||
|
assert "server-name" in result.output
|
||||||
|
assert (tmp_path / ".env").read_text() == "LANGSMITH_DEPLOYMENT_NAME=legacy\n"
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_update(deployment_api):
|
||||||
|
state, requests, build = deployment_api
|
||||||
|
state["resources"] = [{"id": "existing-id", "is_preview": False}]
|
||||||
|
result = CliRunner().invoke(cli, AGENT_ARGS)
|
||||||
|
assert result.exit_code == 0, result.output
|
||||||
|
assert len(requests) == 1
|
||||||
|
assert build.call_args.kwargs["deployment_id"] == "existing-id"
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_rejects_explicit_name(deployment_api, monkeypatch):
|
||||||
|
monkeypatch.setenv("LANGSMITH_DEPLOYMENT_NAME", "legacy")
|
||||||
|
_, requests, _ = deployment_api
|
||||||
|
result = CliRunner().invoke(cli, [*AGENT_ARGS, "--name", "legacy"])
|
||||||
|
assert result.exit_code == 2
|
||||||
|
assert "cannot be combined" in result.output
|
||||||
|
assert not requests
|
||||||
|
|
||||||
|
|
||||||
|
def test_agent_lookup_refuses_a_control_plane_that_ignores_the_filter(deployment_api):
|
||||||
|
state, requests, _ = deployment_api
|
||||||
|
state["resources"] = [
|
||||||
|
{"id": "someone-elses", "is_preview": False},
|
||||||
|
{"id": "another", "is_preview": False},
|
||||||
|
]
|
||||||
|
|
||||||
|
result = CliRunner().invoke(cli, AGENT_ARGS)
|
||||||
|
|
||||||
|
assert result.exit_code != 0
|
||||||
|
assert "does not filter deployments by agent" in result.output
|
||||||
|
assert len(requests) == 1
|
||||||
@@ -13,6 +13,17 @@ import pytest
|
|||||||
|
|
||||||
import langgraph_cli.deploy as deploy_mod
|
import langgraph_cli.deploy as deploy_mod
|
||||||
from langgraph_cli.deploy import (
|
from langgraph_cli.deploy import (
|
||||||
|
ById,
|
||||||
|
ByName,
|
||||||
|
CustomerRegistrySource,
|
||||||
|
DockerBuildCommand,
|
||||||
|
ExistingDeployment,
|
||||||
|
Listener,
|
||||||
|
ManagedRegistrySource,
|
||||||
|
OnListener,
|
||||||
|
RemoteBuildSource,
|
||||||
|
RequestedPlacement,
|
||||||
|
Unplaced,
|
||||||
_call_host_backend_with_optional_tenant,
|
_call_host_backend_with_optional_tenant,
|
||||||
_create_host_backend_client,
|
_create_host_backend_client,
|
||||||
_docker_config_for_token,
|
_docker_config_for_token,
|
||||||
@@ -21,12 +32,14 @@ from langgraph_cli.deploy import (
|
|||||||
_parse_env_from_config,
|
_parse_env_from_config,
|
||||||
_resolve_env_path,
|
_resolve_env_path,
|
||||||
_resolve_pushed_image_digest,
|
_resolve_pushed_image_digest,
|
||||||
_smith_dashboard_base_url,
|
_select_source,
|
||||||
_validate_prebuilt_image,
|
_validate_prebuilt_image,
|
||||||
|
find_deployment_by_name,
|
||||||
normalize_image_tag,
|
normalize_image_tag,
|
||||||
normalize_name,
|
normalize_name,
|
||||||
)
|
)
|
||||||
from langgraph_cli.host_backend import HostBackendClient, HostBackendError
|
from langgraph_cli.host_backend import HostBackendClient, HostBackendError
|
||||||
|
from langgraph_cli.image_reference import ImageReference
|
||||||
|
|
||||||
|
|
||||||
class TestDockerConfigForToken:
|
class TestDockerConfigForToken:
|
||||||
@@ -259,31 +272,29 @@ class TestEnvWithoutDeploymentName:
|
|||||||
|
|
||||||
class TestCallHostBackendWithOptionalTenant:
|
class TestCallHostBackendWithOptionalTenant:
|
||||||
def _make_client(self, handler):
|
def _make_client(self, handler):
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com",
|
||||||
base_url="https://api.example.com",
|
"test-key",
|
||||||
transport=httpx.MockTransport(handler),
|
transport=httpx.MockTransport(handler),
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def _make_eu_client(self, handler):
|
def _make_eu_client(self, handler):
|
||||||
c = HostBackendClient("https://eu.api.host.langchain.com", "test-key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://eu.api.host.langchain.com",
|
||||||
base_url="https://eu.api.host.langchain.com",
|
"test-key",
|
||||||
transport=httpx.MockTransport(handler),
|
transport=httpx.MockTransport(handler),
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
def test_success_passes_through(self):
|
def test_success_passes_through(self):
|
||||||
client = self._make_client(lambda req: httpx.Response(200, json={"ok": True}))
|
client = self._make_client(
|
||||||
|
lambda req: httpx.Response(200, json={"resources": [{"id": "dep-1"}]})
|
||||||
|
)
|
||||||
result = _call_host_backend_with_optional_tenant(
|
result = _call_host_backend_with_optional_tenant(
|
||||||
client, lambda c: c.list_deployments()
|
client, lambda c: c.list_deployments()
|
||||||
)
|
)
|
||||||
assert result == {"ok": True}
|
assert result == [{"id": "dep-1"}]
|
||||||
|
|
||||||
def test_403_not_enabled_gives_actionable_error(self):
|
def test_403_not_enabled_gives_actionable_error(self):
|
||||||
detail = (
|
detail = (
|
||||||
@@ -334,7 +345,6 @@ class TestCallHostBackendWithOptionalTenant:
|
|||||||
assert exc_info.value.status_code == 403
|
assert exc_info.value.status_code == 403
|
||||||
assert "smith.langchain.com" in exc_info.value.message
|
assert "smith.langchain.com" in exc_info.value.message
|
||||||
assert seen_tenant_ids == [None, "workspace-123"]
|
assert seen_tenant_ids == [None, "workspace-123"]
|
||||||
assert client._client.headers["X-Tenant-ID"] == "workspace-123"
|
|
||||||
|
|
||||||
def test_other_403_re_raises_original(self):
|
def test_other_403_re_raises_original(self):
|
||||||
client = self._make_client(
|
client = self._make_client(
|
||||||
@@ -347,7 +357,6 @@ class TestCallHostBackendWithOptionalTenant:
|
|||||||
|
|
||||||
def test_workspace_prompt_blocked_by_no_input(self, monkeypatch):
|
def test_workspace_prompt_blocked_by_no_input(self, monkeypatch):
|
||||||
"""With _no_input=True, 403 requiring workspace should raise ClickException."""
|
"""With _no_input=True, 403 requiring workspace should raise ClickException."""
|
||||||
import langgraph_cli.deploy as deploy_mod
|
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
||||||
|
|
||||||
@@ -515,7 +524,6 @@ class TestEmitterTextMode:
|
|||||||
|
|
||||||
class TestCreateHostBackendClientNoInput:
|
class TestCreateHostBackendClientNoInput:
|
||||||
def test_raises_when_no_api_key_and_no_input(self, monkeypatch, tmp_path):
|
def test_raises_when_no_api_key_and_no_input(self, monkeypatch, tmp_path):
|
||||||
import langgraph_cli.deploy as deploy_mod
|
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
||||||
monkeypatch.delenv("LANGSMITH_API_KEY", raising=False)
|
monkeypatch.delenv("LANGSMITH_API_KEY", raising=False)
|
||||||
@@ -530,7 +538,6 @@ class TestCreateHostBackendClientNoInput:
|
|||||||
)
|
)
|
||||||
|
|
||||||
def test_succeeds_with_api_key_in_env(self, monkeypatch, tmp_path):
|
def test_succeeds_with_api_key_in_env(self, monkeypatch, tmp_path):
|
||||||
import langgraph_cli.deploy as deploy_mod
|
|
||||||
|
|
||||||
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
monkeypatch.setattr(deploy_mod, "_no_input", True)
|
||||||
monkeypatch.setenv("LANGSMITH_API_KEY", "lsv2_test")
|
monkeypatch.setenv("LANGSMITH_API_KEY", "lsv2_test")
|
||||||
@@ -543,60 +550,226 @@ class TestCreateHostBackendClientNoInput:
|
|||||||
assert client is not None
|
assert client is not None
|
||||||
|
|
||||||
|
|
||||||
class TestSmithDashboardBaseUrl:
|
class TestCreateHostBackendClientEndpoint:
|
||||||
def test_none_returns_default(self):
|
def test_langsmith_endpoint_from_project_env_selects_self_hosted_control_plane(
|
||||||
assert _smith_dashboard_base_url(None) == "https://smith.langchain.com"
|
self, monkeypatch
|
||||||
|
):
|
||||||
|
monkeypatch.setenv("LANGSMITH_API_KEY", "lsv2_test")
|
||||||
|
monkeypatch.delenv("LANGSMITH_ENDPOINT", raising=False)
|
||||||
|
|
||||||
def test_empty_returns_default(self):
|
client = _create_host_backend_client(
|
||||||
assert _smith_dashboard_base_url("") == "https://smith.langchain.com"
|
host_url=None,
|
||||||
|
api_key=None,
|
||||||
def test_prod_host_url(self):
|
env_vars={"LANGSMITH_ENDPOINT": "https://smith.example.com/api/v1"},
|
||||||
assert (
|
|
||||||
_smith_dashboard_base_url("https://api.host.langchain.com")
|
|
||||||
== "https://smith.langchain.com"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_dev_host_url(self):
|
assert client.base_url == "https://smith.example.com/api-host"
|
||||||
assert (
|
|
||||||
_smith_dashboard_base_url("https://dev.api.host.langchain.com")
|
def test_explicit_host_url_wins_over_langsmith_endpoint(self, monkeypatch):
|
||||||
== "https://dev.smith.langchain.com"
|
monkeypatch.setenv("LANGSMITH_API_KEY", "lsv2_test")
|
||||||
|
monkeypatch.setenv("LANGSMITH_ENDPOINT", "https://smith.example.com/api/v1")
|
||||||
|
|
||||||
|
client = _create_host_backend_client(
|
||||||
|
host_url="https://custom.host.com", api_key=None, env_vars={}
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_eu_host_url(self):
|
assert client.base_url == "https://custom.host.com"
|
||||||
assert (
|
|
||||||
_smith_dashboard_base_url("https://eu.api.host.langchain.com")
|
|
||||||
== "https://eu.smith.langchain.com"
|
class TestDockerBuildCommand:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("machine", "verbose", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
"x86_64",
|
||||||
|
False,
|
||||||
|
DockerBuildCommand(("docker", "build"), ()),
|
||||||
|
id="amd64_host_builds_natively",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"arm64",
|
||||||
|
False,
|
||||||
|
DockerBuildCommand(
|
||||||
|
("docker", "buildx", "build"),
|
||||||
|
("--platform", "linux/amd64", "--load", "--progress=quiet"),
|
||||||
|
),
|
||||||
|
id="other_hosts_cross_build_quietly",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"arm64",
|
||||||
|
True,
|
||||||
|
DockerBuildCommand(
|
||||||
|
("docker", "buildx", "build"),
|
||||||
|
("--platform", "linux/amd64", "--load"),
|
||||||
|
),
|
||||||
|
id="verbose_cross_build_keeps_progress_output",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_for_host_targets_the_deployment_platform(self, machine, verbose, expected):
|
||||||
|
assert DockerBuildCommand.for_host(machine, verbose=verbose) == expected
|
||||||
|
|
||||||
|
|
||||||
|
class TestSelectSource:
|
||||||
|
OPTIONS = {
|
||||||
|
"push_to": None,
|
||||||
|
"image": None,
|
||||||
|
"image_name": None,
|
||||||
|
"tag": None,
|
||||||
|
"remote_build_flag": None,
|
||||||
|
"placement": RequestedPlacement(),
|
||||||
|
"selector": ByName("my-app"),
|
||||||
|
}
|
||||||
|
REPOSITORY = "registry.example.com/app"
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("flags", "docker_available", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": REPOSITORY},
|
||||||
|
True,
|
||||||
|
CustomerRegistrySource(
|
||||||
|
reference=ImageReference(REPOSITORY, "latest"),
|
||||||
|
prebuilt_image=None,
|
||||||
|
requested_placement=RequestedPlacement(),
|
||||||
|
),
|
||||||
|
id="push_to_selects_the_external_source_with_the_default_tag",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": f"{REPOSITORY}:v2"},
|
||||||
|
True,
|
||||||
|
CustomerRegistrySource(
|
||||||
|
reference=ImageReference(REPOSITORY, "v2"),
|
||||||
|
prebuilt_image=None,
|
||||||
|
requested_placement=RequestedPlacement(),
|
||||||
|
),
|
||||||
|
id="push_to_keeps_a_tag_given_in_the_reference",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": REPOSITORY, "tag": "v3"},
|
||||||
|
True,
|
||||||
|
CustomerRegistrySource(
|
||||||
|
reference=ImageReference(REPOSITORY, "v3"),
|
||||||
|
prebuilt_image=None,
|
||||||
|
requested_placement=RequestedPlacement(),
|
||||||
|
),
|
||||||
|
id="tag_flag_composes_with_push_to",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": REPOSITORY, "image": "app:dev"},
|
||||||
|
False,
|
||||||
|
CustomerRegistrySource(
|
||||||
|
reference=ImageReference(REPOSITORY, "latest"),
|
||||||
|
prebuilt_image="app:dev",
|
||||||
|
requested_placement=RequestedPlacement(),
|
||||||
|
),
|
||||||
|
id="prebuilt_image_is_retagged_for_push_to_without_docker_checks",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{
|
||||||
|
"push_to": REPOSITORY,
|
||||||
|
"placement": RequestedPlacement("listener-1", "agents"),
|
||||||
|
},
|
||||||
|
True,
|
||||||
|
CustomerRegistrySource(
|
||||||
|
reference=ImageReference(REPOSITORY, "latest"),
|
||||||
|
prebuilt_image=None,
|
||||||
|
requested_placement=RequestedPlacement("listener-1", "agents"),
|
||||||
|
),
|
||||||
|
id="push_to_carries_the_requested_placement",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"remote_build_flag": True},
|
||||||
|
True,
|
||||||
|
RemoteBuildSource(),
|
||||||
|
id="remote_flag_selects_the_source_upload",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{},
|
||||||
|
False,
|
||||||
|
RemoteBuildSource(),
|
||||||
|
id="no_local_docker_falls_back_to_the_source_upload",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{},
|
||||||
|
True,
|
||||||
|
ManagedRegistrySource(
|
||||||
|
prebuilt_image=None, image_name=None, tag="latest"
|
||||||
|
),
|
||||||
|
id="local_docker_selects_the_internal_docker_source",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"image": "app:dev", "tag": "v1"},
|
||||||
|
False,
|
||||||
|
ManagedRegistrySource(
|
||||||
|
prebuilt_image="app:dev", image_name=None, tag="v1"
|
||||||
|
),
|
||||||
|
id="prebuilt_image_forces_the_internal_docker_source",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_flags_select_one_source(
|
||||||
|
self, monkeypatch, mocker, flags, docker_available, expected
|
||||||
|
):
|
||||||
|
mocker.patch(
|
||||||
|
"langgraph_cli.deploy._get_emitter", return_value=mocker.MagicMock()
|
||||||
|
)
|
||||||
|
monkeypatch.setattr(
|
||||||
|
deploy_mod,
|
||||||
|
"can_build_locally",
|
||||||
|
lambda: (True, None) if docker_available else (False, "Docker is required"),
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_staging_host_url(self):
|
assert _select_source(**{**self.OPTIONS, **flags}) == expected
|
||||||
assert (
|
|
||||||
_smith_dashboard_base_url("https://staging.api.host.langchain.com")
|
def test_push_to_build_requires_local_docker(self, monkeypatch):
|
||||||
== "https://staging.smith.langchain.com"
|
monkeypatch.setattr(
|
||||||
|
deploy_mod, "can_build_locally", lambda: (False, "Docker is required")
|
||||||
)
|
)
|
||||||
|
|
||||||
def test_localhost(self):
|
with pytest.raises(click.UsageError, match="Docker is required"):
|
||||||
assert (
|
_select_source(**{**self.OPTIONS, "push_to": self.REPOSITORY})
|
||||||
_smith_dashboard_base_url("http://localhost:8080")
|
|
||||||
== "http://localhost:8080"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_localhost_trailing_slash(self):
|
@pytest.mark.parametrize(
|
||||||
assert (
|
("flags", "message"),
|
||||||
_smith_dashboard_base_url("http://localhost:8080/")
|
[
|
||||||
== "http://localhost:8080"
|
pytest.param(
|
||||||
|
{"push_to": REPOSITORY, "remote_build_flag": True},
|
||||||
|
"--push-to cannot be combined with --remote.",
|
||||||
|
id="push_to_with_remote",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": f"{REPOSITORY}:v1", "tag": "v2"},
|
||||||
|
"already includes a tag",
|
||||||
|
id="push_to_with_a_tag_and_the_tag_flag",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"push_to": f"{REPOSITORY}@sha256:abc"},
|
||||||
|
"not a digest",
|
||||||
|
id="push_to_with_a_digest",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"image": "app:dev", "remote_build_flag": True},
|
||||||
|
"--image cannot be combined with --remote builds.",
|
||||||
|
id="image_with_remote",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"placement": RequestedPlacement(listener_id="listener-1")},
|
||||||
|
"only apply when creating a deployment with --push-to",
|
||||||
|
id="listener_without_push_to",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"placement": RequestedPlacement(k8s_namespace="agents")},
|
||||||
|
"only apply when creating a deployment with --push-to",
|
||||||
|
id="namespace_without_push_to",
|
||||||
|
),
|
||||||
|
],
|
||||||
)
|
)
|
||||||
|
def test_conflicting_flags_are_rejected(self, monkeypatch, flags, message):
|
||||||
|
monkeypatch.setattr(deploy_mod, "can_build_locally", lambda: (True, None))
|
||||||
|
|
||||||
def test_127_0_0_1(self):
|
with pytest.raises(click.UsageError, match=message):
|
||||||
assert (
|
_select_source(**{**self.OPTIONS, **flags})
|
||||||
_smith_dashboard_base_url("http://127.0.0.1:3000")
|
|
||||||
== "http://127.0.0.1:3000"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_unknown_domain_returns_default(self):
|
|
||||||
assert (
|
|
||||||
_smith_dashboard_base_url("https://custom.example.com")
|
|
||||||
== "https://smith.langchain.com"
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class TestResolvePushedImageDigest:
|
class TestResolvePushedImageDigest:
|
||||||
@@ -647,6 +820,16 @@ class TestResolvePushedImageDigest:
|
|||||||
)
|
)
|
||||||
assert out == "us-central1-docker.pkg.dev/proj/repo@sha256:abc123"
|
assert out == "us-central1-docker.pkg.dev/proj/repo@sha256:abc123"
|
||||||
|
|
||||||
|
def test_registry_port_without_tag_still_resolves_the_digest(self):
|
||||||
|
runner = self._runner('["localhost:5000/repo@sha256:abc123"]')
|
||||||
|
out = _resolve_pushed_image_digest(
|
||||||
|
runner,
|
||||||
|
remote_image="localhost:5000/repo",
|
||||||
|
docker_config_dir=None,
|
||||||
|
verbose=False,
|
||||||
|
)
|
||||||
|
assert out == "localhost:5000/repo@sha256:abc123"
|
||||||
|
|
||||||
def test_empty_repodigests_falls_back_with_warning(self, mocker):
|
def test_empty_repodigests_falls_back_with_warning(self, mocker):
|
||||||
emitter = mocker.MagicMock()
|
emitter = mocker.MagicMock()
|
||||||
mocker.patch("langgraph_cli.deploy._get_emitter", return_value=emitter)
|
mocker.patch("langgraph_cli.deploy._get_emitter", return_value=emitter)
|
||||||
@@ -750,3 +933,289 @@ class TestResolvePushedImageDigest:
|
|||||||
frame_locals = captured["coro"].cr_frame.f_locals
|
frame_locals = captured["coro"].cr_frame.f_locals
|
||||||
assert "--config" not in frame_locals["args"]
|
assert "--config" not in frame_locals["args"]
|
||||||
captured["coro"].close()
|
captured["coro"].close()
|
||||||
|
|
||||||
|
|
||||||
|
class TestListener:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("resource", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
{
|
||||||
|
"id": "listener-1",
|
||||||
|
"compute_id": "prod-cluster",
|
||||||
|
"compute_config": {"k8s_namespaces": ["agents", "agents-staging"]},
|
||||||
|
},
|
||||||
|
Listener("listener-1", "prod-cluster", ("agents", "agents-staging")),
|
||||||
|
id="reads_id_cluster_and_namespaces",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"id": "listener-1", "compute_id": "c", "compute_config": {}},
|
||||||
|
Listener("listener-1", "c", ()),
|
||||||
|
id="missing_namespaces",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"id": "listener-1", "compute_id": "c", "compute_config": None},
|
||||||
|
Listener("listener-1", "c", ()),
|
||||||
|
id="null_compute_config",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"id": "listener-1"},
|
||||||
|
Listener("listener-1", "", ()),
|
||||||
|
id="only_an_id",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_from_resource_reads_the_control_plane_shape(self, resource, expected):
|
||||||
|
assert Listener.from_resource(resource) == expected
|
||||||
|
|
||||||
|
|
||||||
|
ONE_NAMESPACE = Listener("listener-1", "prod-cluster", ("agents",))
|
||||||
|
TWO_NAMESPACES = Listener("listener-2", "multi-cluster", ("agents", "agents-staging"))
|
||||||
|
NO_NAMESPACE = Listener("listener-3", "broken-cluster", ())
|
||||||
|
|
||||||
|
|
||||||
|
class TestRequestedPlacement:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("request_", "listeners", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(), (), Unplaced(), id="no_listeners_no_request"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(),
|
||||||
|
(ONE_NAMESPACE,),
|
||||||
|
OnListener("listener-1", "agents"),
|
||||||
|
id="uses_the_only_possible_answer",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(k8s_namespace="agents-staging"),
|
||||||
|
(TWO_NAMESPACES,),
|
||||||
|
OnListener("listener-2", "agents-staging"),
|
||||||
|
id="namespace_alone_picks_the_only_listener",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_resolves_to_a_placement(self, request_, listeners, expected):
|
||||||
|
assert request_.among(listeners) == expected
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("request_", "listeners", "message"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-1"),
|
||||||
|
(),
|
||||||
|
"no listeners",
|
||||||
|
id="workspace_has_no_listeners",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(),
|
||||||
|
(ONE_NAMESPACE, TWO_NAMESPACES),
|
||||||
|
"--listener-id",
|
||||||
|
id="several_listeners_need_a_choice",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(k8s_namespace="agents"),
|
||||||
|
(ONE_NAMESPACE, TWO_NAMESPACES),
|
||||||
|
"--listener-id",
|
||||||
|
id="namespace_alone_is_ambiguous_with_several_listeners",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(k8s_namespace="agents"),
|
||||||
|
(),
|
||||||
|
"no listeners",
|
||||||
|
id="namespace_without_any_listener",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(),
|
||||||
|
(TWO_NAMESPACES,),
|
||||||
|
"--k8s-namespace",
|
||||||
|
id="several_namespaces_need_a_choice",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_refuses_and_names_the_choices(self, request_, listeners, message):
|
||||||
|
with pytest.raises(click.UsageError, match=message):
|
||||||
|
request_.among(listeners)
|
||||||
|
|
||||||
|
def test_the_error_lists_every_listener_with_its_cluster_and_namespaces(self):
|
||||||
|
with pytest.raises(click.UsageError) as error:
|
||||||
|
RequestedPlacement().among((ONE_NAMESPACE, TWO_NAMESPACES))
|
||||||
|
|
||||||
|
assert "listener-1" in error.value.message
|
||||||
|
assert "prod-cluster" in error.value.message
|
||||||
|
assert "agents-staging" in error.value.message
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("placement", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(Unplaced(), {}, id="unplaced_adds_nothing"),
|
||||||
|
pytest.param(
|
||||||
|
OnListener("listener-1", "agents"),
|
||||||
|
{
|
||||||
|
"listener_id": "listener-1",
|
||||||
|
"listener_config": {"k8s_namespace": "agents"},
|
||||||
|
},
|
||||||
|
id="placed_carries_listener_and_namespace",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_source_config_matches_the_control_plane_shape(self, placement, expected):
|
||||||
|
assert placement.source_config() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_finding_a_deployment_by_name_narrows_the_search_for_every_server_version():
|
||||||
|
seen: dict = {}
|
||||||
|
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
seen["params"] = dict(req.url.params)
|
||||||
|
return httpx.Response(
|
||||||
|
200,
|
||||||
|
json={"resources": [{"id": "dep-1", "name": "agent", "source": "github"}]},
|
||||||
|
)
|
||||||
|
|
||||||
|
client = HostBackendClient(
|
||||||
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
|
)
|
||||||
|
|
||||||
|
found = find_deployment_by_name(client, "agent")
|
||||||
|
|
||||||
|
assert seen["params"] == {
|
||||||
|
"name": "agent",
|
||||||
|
"name_contains": "agent",
|
||||||
|
"limit": "100",
|
||||||
|
}
|
||||||
|
assert found == ExistingDeployment("dep-1", "github")
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_server_that_ignores_the_exact_name_filter_never_matches_another_deployment():
|
||||||
|
client = HostBackendClient(
|
||||||
|
"https://api.example.com",
|
||||||
|
"key",
|
||||||
|
transport=httpx.MockTransport(
|
||||||
|
lambda req: httpx.Response(
|
||||||
|
200,
|
||||||
|
json={
|
||||||
|
"resources": [
|
||||||
|
{
|
||||||
|
"id": "dep-other",
|
||||||
|
"name": "another-teams-agent",
|
||||||
|
"source": "external_docker",
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert find_deployment_by_name(client, "brand-new-agent") is None
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_full_page_without_a_match_refuses_to_claim_the_name_is_free():
|
||||||
|
page = [
|
||||||
|
{"id": f"dep-{index}", "name": f"other-agent-{index}"} for index in range(100)
|
||||||
|
]
|
||||||
|
client = HostBackendClient(
|
||||||
|
"https://api.example.com",
|
||||||
|
"key",
|
||||||
|
transport=httpx.MockTransport(
|
||||||
|
lambda req: httpx.Response(200, json={"resources": page})
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(click.ClickException, match="--deployment-id"):
|
||||||
|
find_deployment_by_name(client, "brand-new-agent")
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_partial_page_without_a_match_means_the_name_is_free():
|
||||||
|
client = HostBackendClient(
|
||||||
|
"https://api.example.com",
|
||||||
|
"key",
|
||||||
|
transport=httpx.MockTransport(
|
||||||
|
lambda req: httpx.Response(
|
||||||
|
200, json={"resources": [{"id": "dep-1", "name": "other"}]}
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert find_deployment_by_name(client, "brand-new-agent") is None
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"resource",
|
||||||
|
[
|
||||||
|
pytest.param({"compute_id": "c"}, id="no_id"),
|
||||||
|
pytest.param({"id": ""}, id="empty_id"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_a_listener_without_an_id_is_refused(resource):
|
||||||
|
with pytest.raises(HostBackendError, match="without an id"):
|
||||||
|
Listener.from_resource(resource)
|
||||||
|
|
||||||
|
|
||||||
|
def test_a_deployment_id_with_listener_flags_is_refused_without_probing_docker(
|
||||||
|
monkeypatch,
|
||||||
|
):
|
||||||
|
def explode() -> tuple[bool, str | None]:
|
||||||
|
raise AssertionError("docker must not be probed for an argv-only conflict")
|
||||||
|
|
||||||
|
monkeypatch.setattr(deploy_mod, "can_build_locally", explode)
|
||||||
|
|
||||||
|
with pytest.raises(click.UsageError, match="--deployment-id"):
|
||||||
|
_select_source(
|
||||||
|
push_to="registry.example.com/app",
|
||||||
|
image=None,
|
||||||
|
image_name=None,
|
||||||
|
tag=None,
|
||||||
|
remote_build_flag=None,
|
||||||
|
placement=RequestedPlacement(listener_id="listener-1"),
|
||||||
|
selector=ById("dep-1"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TestPlacementOnAKnownListener:
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("request_", "listener", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-1"),
|
||||||
|
ONE_NAMESPACE,
|
||||||
|
OnListener("listener-1", "agents"),
|
||||||
|
id="the_only_namespace_is_used",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-2", k8s_namespace="agents"),
|
||||||
|
TWO_NAMESPACES,
|
||||||
|
OnListener("listener-2", "agents"),
|
||||||
|
id="the_chosen_namespace_is_used",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_places_on_the_listener(self, request_, listener, expected):
|
||||||
|
assert request_.on(listener) == expected
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("request_", "listener", "message"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-2"),
|
||||||
|
TWO_NAMESPACES,
|
||||||
|
"--k8s-namespace",
|
||||||
|
id="several_namespaces_need_a_choice",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-2", k8s_namespace="nope"),
|
||||||
|
TWO_NAMESPACES,
|
||||||
|
"does not serve namespace",
|
||||||
|
id="unknown_namespace",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
RequestedPlacement(listener_id="listener-3"),
|
||||||
|
NO_NAMESPACE,
|
||||||
|
"serves no namespaces",
|
||||||
|
id="listener_without_namespaces",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_refuses_and_names_the_namespaces(self, request_, listener, message):
|
||||||
|
with pytest.raises(click.UsageError, match=message):
|
||||||
|
request_.on(listener)
|
||||||
|
|||||||
@@ -3,29 +3,16 @@ import json
|
|||||||
import httpx
|
import httpx
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
from langgraph_cli.host_backend import HostBackendClient, HostBackendError
|
from langgraph_cli.host_backend import (
|
||||||
|
ControlPlaneEndpoints,
|
||||||
|
HostBackendClient,
|
||||||
@pytest.fixture
|
HostBackendError,
|
||||||
def mock_transport():
|
)
|
||||||
return httpx.MockTransport(lambda req: httpx.Response(200, json={"ok": True}))
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def client(mock_transport):
|
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
|
||||||
c._client = httpx.Client(
|
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=mock_transport,
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
return c
|
|
||||||
|
|
||||||
|
|
||||||
def test_constructor_strips_trailing_slash():
|
def test_constructor_strips_trailing_slash():
|
||||||
c = HostBackendClient("https://api.example.com/", "key")
|
c = HostBackendClient("https://api.example.com/", "key")
|
||||||
assert str(c._client.base_url) == "https://api.example.com"
|
assert c.base_url == "https://api.example.com"
|
||||||
|
|
||||||
|
|
||||||
def test_constructor_empty_url_raises():
|
def test_constructor_empty_url_raises():
|
||||||
@@ -39,12 +26,8 @@ def test_request_sends_headers():
|
|||||||
assert req.headers["accept"] == "application/json"
|
assert req.headers["accept"] == "application/json"
|
||||||
return httpx.Response(200, json={"ok": True})
|
return httpx.Response(200, json={"ok": True})
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "test-key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
result = c._request("GET", "/test")
|
result = c._request("GET", "/test")
|
||||||
assert result == {"ok": True}
|
assert result == {"ok": True}
|
||||||
@@ -56,12 +39,8 @@ def test_request_sends_json_payload():
|
|||||||
assert req.content == b'{"key":"value"}'
|
assert req.content == b'{"key":"value"}'
|
||||||
return httpx.Response(200, json={"created": True})
|
return httpx.Response(200, json={"created": True})
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "test-key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
result = c._request("POST", "/test", {"key": "value"})
|
result = c._request("POST", "/test", {"key": "value"})
|
||||||
assert result == {"created": True}
|
assert result == {"created": True}
|
||||||
@@ -69,25 +48,13 @@ def test_request_sends_json_payload():
|
|||||||
|
|
||||||
def test_request_empty_body_returns_none():
|
def test_request_empty_body_returns_none():
|
||||||
transport = httpx.MockTransport(lambda req: httpx.Response(200, content=b""))
|
transport = httpx.MockTransport(lambda req: httpx.Response(200, content=b""))
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient("https://api.example.com", "test-key", transport=transport)
|
||||||
c._client = httpx.Client(
|
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=transport,
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
assert c._request("DELETE", "/test") is None
|
assert c._request("DELETE", "/test") is None
|
||||||
|
|
||||||
|
|
||||||
def test_request_http_error_raises():
|
def test_request_http_error_raises():
|
||||||
transport = httpx.MockTransport(lambda req: httpx.Response(404, text="not found"))
|
transport = httpx.MockTransport(lambda req: httpx.Response(404, text="not found"))
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient("https://api.example.com", "test-key", transport=transport)
|
||||||
c._client = httpx.Client(
|
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=transport,
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
with pytest.raises(HostBackendError, match="404"):
|
with pytest.raises(HostBackendError, match="404"):
|
||||||
c._request("GET", "/missing")
|
c._request("GET", "/missing")
|
||||||
|
|
||||||
@@ -96,13 +63,7 @@ def test_request_invalid_json_raises():
|
|||||||
transport = httpx.MockTransport(
|
transport = httpx.MockTransport(
|
||||||
lambda req: httpx.Response(200, content=b"not json")
|
lambda req: httpx.Response(200, content=b"not json")
|
||||||
)
|
)
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient("https://api.example.com", "test-key", transport=transport)
|
||||||
c._client = httpx.Client(
|
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=transport,
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
with pytest.raises(HostBackendError, match="Failed to decode"):
|
with pytest.raises(HostBackendError, match="Failed to decode"):
|
||||||
c._request("GET", "/bad-json")
|
c._request("GET", "/bad-json")
|
||||||
|
|
||||||
@@ -111,84 +72,20 @@ def test_request_transport_error_raises():
|
|||||||
def handler(req: httpx.Request) -> httpx.Response:
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
raise httpx.ConnectError("connection refused")
|
raise httpx.ConnectError("connection refused")
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "test-key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
with pytest.raises(HostBackendError, match="connection refused"):
|
with pytest.raises(HostBackendError, match="connection refused"):
|
||||||
c._request("GET", "/test")
|
c._request("GET", "/test")
|
||||||
|
|
||||||
|
|
||||||
def test_create_deployment(client):
|
|
||||||
result = client.create_deployment(
|
|
||||||
name="my-deploy", deployment_type="dev", source="internal_docker"
|
|
||||||
)
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_deployment(client):
|
|
||||||
result = client.get_deployment("dep-123")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_list_deployments(client):
|
|
||||||
result = client.list_deployments("my-app")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_list_deployments_sends_query_params():
|
|
||||||
def handler(req: httpx.Request) -> httpx.Response:
|
|
||||||
assert req.url.path == "/v2/deployments"
|
|
||||||
assert req.url.params["name_contains"] == "my app"
|
|
||||||
return httpx.Response(200, json={"ok": True})
|
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "test-key")
|
|
||||||
c._client = httpx.Client(
|
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "test-key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
|
||||||
result = c.list_deployments("my app")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_delete_deployment(client):
|
|
||||||
result = client.delete_deployment("dep-123")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_request_push_token(client):
|
|
||||||
result = client.request_push_token("dep-123")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_update_deployment(client):
|
|
||||||
result = client.update_deployment(
|
|
||||||
"dep-123", "image:latest", secrets=[{"name": "KEY", "value": "val"}]
|
|
||||||
)
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_update_deployment_no_secrets(client):
|
|
||||||
result = client.update_deployment("dep-123", "image:latest")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def _capturing_client(captured: dict) -> HostBackendClient:
|
def _capturing_client(captured: dict) -> HostBackendClient:
|
||||||
def handler(req: httpx.Request) -> httpx.Response:
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
captured["body"] = req.read()
|
captured["body"] = req.read()
|
||||||
return httpx.Response(200, json={"ok": True})
|
return httpx.Response(200, json={"ok": True})
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
return c
|
return c
|
||||||
|
|
||||||
@@ -199,6 +96,7 @@ def test_update_deployment_forwards_tracked_packages():
|
|||||||
c.update_deployment(
|
c.update_deployment(
|
||||||
"dep-123",
|
"dep-123",
|
||||||
"image:latest",
|
"image:latest",
|
||||||
|
revision_source="internal_docker",
|
||||||
tracked_packages=["google-adk:1.0.0"],
|
tracked_packages=["google-adk:1.0.0"],
|
||||||
)
|
)
|
||||||
body = json.loads(captured["body"])
|
body = json.loads(captured["body"])
|
||||||
@@ -209,7 +107,7 @@ def test_update_deployment_forwards_tracked_packages():
|
|||||||
def test_update_deployment_omits_tracked_packages_when_absent():
|
def test_update_deployment_omits_tracked_packages_when_absent():
|
||||||
captured: dict = {}
|
captured: dict = {}
|
||||||
c = _capturing_client(captured)
|
c = _capturing_client(captured)
|
||||||
c.update_deployment("dep-123", "image:latest")
|
c.update_deployment("dep-123", "image:latest", revision_source="internal_docker")
|
||||||
body = json.loads(captured["body"])
|
body = json.loads(captured["body"])
|
||||||
assert "tracked_packages" not in body
|
assert "tracked_packages" not in body
|
||||||
|
|
||||||
@@ -241,33 +139,14 @@ def test_update_deployment_internal_source_omits_tracked_packages_when_absent():
|
|||||||
assert "tracked_packages" not in body
|
assert "tracked_packages" not in body
|
||||||
|
|
||||||
|
|
||||||
def test_list_revisions(client):
|
|
||||||
result = client.list_revisions("dep-123", limit=5)
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_revision(client):
|
|
||||||
result = client.get_revision("dep-123", "rev-456")
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_build_logs(client):
|
|
||||||
result = client.get_build_logs("proj-1", "rev-1", {"limit": 10})
|
|
||||||
assert result == {"ok": True}
|
|
||||||
|
|
||||||
|
|
||||||
def test_get_deploy_logs_all_revisions():
|
def test_get_deploy_logs_all_revisions():
|
||||||
def handler(req: httpx.Request) -> httpx.Response:
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
assert "/v1/projects/proj-1/deploy_logs" in str(req.url)
|
assert "/v1/projects/proj-1/deploy_logs" in str(req.url)
|
||||||
assert "/revisions/" not in str(req.url)
|
assert "/revisions/" not in str(req.url)
|
||||||
return httpx.Response(200, json={"logs": [{"message": "running"}]})
|
return httpx.Response(200, json={"logs": [{"message": "running"}]})
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
result = c.get_deploy_logs("proj-1", {"limit": 10})
|
result = c.get_deploy_logs("proj-1", {"limit": 10})
|
||||||
assert result == {"logs": [{"message": "running"}]}
|
assert result == {"logs": [{"message": "running"}]}
|
||||||
@@ -278,12 +157,520 @@ def test_get_deploy_logs_specific_revision():
|
|||||||
assert "/v1/projects/proj-1/revisions/rev-2/deploy_logs" in str(req.url)
|
assert "/v1/projects/proj-1/revisions/rev-2/deploy_logs" in str(req.url)
|
||||||
return httpx.Response(200, json={"logs": []})
|
return httpx.Response(200, json={"logs": []})
|
||||||
|
|
||||||
c = HostBackendClient("https://api.example.com", "key")
|
c = HostBackendClient(
|
||||||
c._client = httpx.Client(
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
base_url="https://api.example.com",
|
|
||||||
transport=httpx.MockTransport(handler),
|
|
||||||
headers={"X-Api-Key": "key", "Accept": "application/json"},
|
|
||||||
timeout=30,
|
|
||||||
)
|
)
|
||||||
result = c.get_deploy_logs("proj-1", {"limit": 10}, revision_id="rev-2")
|
result = c.get_deploy_logs("proj-1", {"limit": 10}, revision_id="rev-2")
|
||||||
assert result == {"logs": []}
|
assert result == {"logs": []}
|
||||||
|
|
||||||
|
|
||||||
|
def _routing_client(seen: dict) -> HostBackendClient:
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
seen["method"] = req.method
|
||||||
|
seen["url"] = str(req.url)
|
||||||
|
return httpx.Response(200, json={"ok": True})
|
||||||
|
|
||||||
|
c = HostBackendClient(
|
||||||
|
"https://api.example.com/prefix", "key", transport=httpx.MockTransport(handler)
|
||||||
|
)
|
||||||
|
return c
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("call", "expected_body"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.create_deployment(
|
||||||
|
name="my-deploy",
|
||||||
|
source="internal_docker",
|
||||||
|
source_config={"deployment_type": "dev"},
|
||||||
|
source_revision_config={},
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"name": "my-deploy",
|
||||||
|
"source": "internal_docker",
|
||||||
|
"source_config": {"deployment_type": "dev"},
|
||||||
|
"source_revision_config": {},
|
||||||
|
},
|
||||||
|
id="internal_docker_create_omits_secrets_key_when_not_given",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.create_deployment(
|
||||||
|
name="my-deploy",
|
||||||
|
source="internal_docker",
|
||||||
|
source_config={"deployment_type": "prod"},
|
||||||
|
source_revision_config={},
|
||||||
|
secrets=[{"name": "KEY", "value": "val"}],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"name": "my-deploy",
|
||||||
|
"source": "internal_docker",
|
||||||
|
"source_config": {"deployment_type": "prod"},
|
||||||
|
"source_revision_config": {},
|
||||||
|
"secrets": [{"name": "KEY", "value": "val"}],
|
||||||
|
},
|
||||||
|
id="internal_docker_create_forwards_secrets",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment(
|
||||||
|
"dep-123",
|
||||||
|
"registry.example.com/app@sha256:abc",
|
||||||
|
revision_source="internal_docker",
|
||||||
|
secrets=[{"name": "KEY", "value": "val"}],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"revision_source": "internal_docker",
|
||||||
|
"source_revision_config": {
|
||||||
|
"image_uri": "registry.example.com/app@sha256:abc"
|
||||||
|
},
|
||||||
|
"secrets": [{"name": "KEY", "value": "val"}],
|
||||||
|
},
|
||||||
|
id="internal_docker_revision_names_its_source",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment_internal_source(
|
||||||
|
"dep-123",
|
||||||
|
source_tarball_path="tarballs/src.tgz",
|
||||||
|
config_path="langgraph.json",
|
||||||
|
secrets=[],
|
||||||
|
install_command="yarn install",
|
||||||
|
build_command="yarn build",
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"revision_source": "internal_source",
|
||||||
|
"source_revision_config": {
|
||||||
|
"source_tarball_path": "tarballs/src.tgz",
|
||||||
|
"langgraph_config_path": "langgraph.json",
|
||||||
|
},
|
||||||
|
"source_config": {
|
||||||
|
"install_command": "yarn install",
|
||||||
|
"build_command": "yarn build",
|
||||||
|
},
|
||||||
|
"secrets": [],
|
||||||
|
},
|
||||||
|
id="internal_source_revision_sends_js_build_commands",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment_internal_source(
|
||||||
|
"dep-123",
|
||||||
|
source_tarball_path="tarballs/src.tgz",
|
||||||
|
config_path="langgraph.json",
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"revision_source": "internal_source",
|
||||||
|
"source_revision_config": {
|
||||||
|
"source_tarball_path": "tarballs/src.tgz",
|
||||||
|
"langgraph_config_path": "langgraph.json",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
id="internal_source_revision_omits_source_config_without_commands",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.create_deployment(
|
||||||
|
name="agent",
|
||||||
|
source="external_docker",
|
||||||
|
source_config={"resource_spec": {}},
|
||||||
|
source_revision_config={
|
||||||
|
"image_uri": "registry.example.com/agent@sha256:1"
|
||||||
|
},
|
||||||
|
secrets=[],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"name": "agent",
|
||||||
|
"source": "external_docker",
|
||||||
|
"source_config": {"resource_spec": {}},
|
||||||
|
"source_revision_config": {
|
||||||
|
"image_uri": "registry.example.com/agent@sha256:1"
|
||||||
|
},
|
||||||
|
"secrets": [],
|
||||||
|
},
|
||||||
|
id="create_sends_the_source_configs_as_given",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment(
|
||||||
|
"dep-1", "registry.example.com/agent@sha256:2", revision_source=None
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"source_revision_config": {
|
||||||
|
"image_uri": "registry.example.com/agent@sha256:2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
id="revision_without_source_override_omits_revision_source",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment(
|
||||||
|
"dep-1",
|
||||||
|
"registry.example.com/agent@sha256:2",
|
||||||
|
revision_source="internal_docker",
|
||||||
|
tracked_packages=["langgraph:1.0.0"],
|
||||||
|
),
|
||||||
|
{
|
||||||
|
"revision_source": "internal_docker",
|
||||||
|
"source_revision_config": {
|
||||||
|
"image_uri": "registry.example.com/agent@sha256:2"
|
||||||
|
},
|
||||||
|
"tracked_packages": ["langgraph:1.0.0"],
|
||||||
|
},
|
||||||
|
id="revision_with_source_override_names_it",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_request_body_matches_control_plane_contract(call, expected_body):
|
||||||
|
captured: dict = {}
|
||||||
|
call(_capturing_client(captured))
|
||||||
|
assert json.loads(captured["body"]) == expected_body
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("call", "method", "route"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.create_deployment(
|
||||||
|
name="n",
|
||||||
|
source="internal_docker",
|
||||||
|
source_config={"deployment_type": "dev"},
|
||||||
|
source_revision_config={},
|
||||||
|
),
|
||||||
|
"POST",
|
||||||
|
"/v2/deployments",
|
||||||
|
id="create_deployment",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.get_deployment("dep-1"),
|
||||||
|
"GET",
|
||||||
|
"/v2/deployments/dep-1",
|
||||||
|
id="get_deployment",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.delete_deployment("dep-1"),
|
||||||
|
"DELETE",
|
||||||
|
"/v2/deployments/dep-1",
|
||||||
|
id="delete_deployment",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.update_deployment("dep-1", "img", revision_source=None),
|
||||||
|
"PATCH",
|
||||||
|
"/v2/deployments/dep-1",
|
||||||
|
id="patch_deployment",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.request_push_token("dep-1"),
|
||||||
|
"POST",
|
||||||
|
"/v2/deployments/dep-1/push-token",
|
||||||
|
id="push_token",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.request_upload_url("dep-1"),
|
||||||
|
"POST",
|
||||||
|
"/v2/deployments/dep-1/upload-url",
|
||||||
|
id="upload_url",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.list_revisions("dep-1", limit=5),
|
||||||
|
"GET",
|
||||||
|
"/v2/deployments/dep-1/revisions?limit=5",
|
||||||
|
id="list_revisions_puts_limit_in_query",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.get_revision("dep-1", "rev-2"),
|
||||||
|
"GET",
|
||||||
|
"/v2/deployments/dep-1/revisions/rev-2",
|
||||||
|
id="get_revision",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.get_build_logs("dep-1", "rev-2", {"limit": 10}),
|
||||||
|
"POST",
|
||||||
|
"/v1/projects/dep-1/revisions/rev-2/build_logs",
|
||||||
|
id="build_logs",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_request_targets_control_plane_route_under_base_url(call, method, route):
|
||||||
|
seen: dict = {}
|
||||||
|
call(_routing_client(seen))
|
||||||
|
assert (seen["method"], seen["url"]) == (
|
||||||
|
method,
|
||||||
|
f"https://api.example.com/prefix{route}",
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_injected_transport_receives_requests_under_the_prefixed_base_url():
|
||||||
|
seen: dict = {}
|
||||||
|
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
seen["url"] = str(req.url)
|
||||||
|
seen["api_key"] = req.headers["x-api-key"]
|
||||||
|
return httpx.Response(200, json={"ok": True})
|
||||||
|
|
||||||
|
c = HostBackendClient(
|
||||||
|
"https://smith.example.com/api-host",
|
||||||
|
"key",
|
||||||
|
transport=httpx.MockTransport(handler),
|
||||||
|
)
|
||||||
|
|
||||||
|
assert c.list_revisions("dep-1", limit=2) == []
|
||||||
|
assert seen == {
|
||||||
|
"url": "https://smith.example.com/api-host/v2/deployments/dep-1/revisions?limit=2",
|
||||||
|
"api_key": "key",
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
CLOUD = ("https://api.host.langchain.com", "https://smith.langchain.com")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("host_url", "langsmith_endpoint", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(None, None, CLOUD, id="nothing_configured_targets_cloud"),
|
||||||
|
pytest.param(
|
||||||
|
None, "https://api.smith.langchain.com", CLOUD, id="cloud_langsmith_api"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://api.smith.langchain.com/api/v1",
|
||||||
|
CLOUD,
|
||||||
|
id="cloud_langsmith_api_with_versioned_path",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None, "https://api.langchain.com", CLOUD, id="cloud_langchain_api_alias"
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://xapi.smith.langchain.com",
|
||||||
|
CLOUD,
|
||||||
|
id="lookalike_cloud_host_is_not_rewritten_into_a_control_plane",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://eu.api.smith.langchain.com",
|
||||||
|
("https://eu.api.host.langchain.com", "https://eu.smith.langchain.com"),
|
||||||
|
id="eu_cloud_maps_to_eu_control_plane",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://dev.api.smith.langchain.com",
|
||||||
|
("https://dev.api.host.langchain.com", "https://dev.smith.langchain.com"),
|
||||||
|
id="dev_cloud_maps_to_dev_control_plane",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://aks.smith.langchain.dev/api",
|
||||||
|
(
|
||||||
|
"https://aks.smith.langchain.dev/api-host",
|
||||||
|
"https://aks.smith.langchain.dev",
|
||||||
|
),
|
||||||
|
id="self_hosted_api_path_becomes_api_host",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://smith.example.com/api/v1",
|
||||||
|
("https://smith.example.com/api-host", "https://smith.example.com"),
|
||||||
|
id="self_hosted_versioned_api_path_becomes_api_host",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://smith.example.com",
|
||||||
|
("https://smith.example.com/api-host", "https://smith.example.com"),
|
||||||
|
id="self_hosted_origin_gets_api_host_appended",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
None,
|
||||||
|
"https://corp.example.com/langsmith/api/v1",
|
||||||
|
(
|
||||||
|
"https://corp.example.com/langsmith/api-host",
|
||||||
|
"https://corp.example.com/langsmith",
|
||||||
|
),
|
||||||
|
id="self_hosted_path_prefix_is_kept",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"https://custom.host.example",
|
||||||
|
"https://aks.smith.langchain.dev/api",
|
||||||
|
("https://custom.host.example", "https://smith.langchain.com"),
|
||||||
|
id="explicit_host_url_beats_langsmith_endpoint",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"https://api.host.langchain.com",
|
||||||
|
"https://aks.smith.langchain.dev/api",
|
||||||
|
CLOUD,
|
||||||
|
id="explicit_cloud_host_url_beats_self_hosted_endpoint",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"https://smith.example.com/api-host/",
|
||||||
|
None,
|
||||||
|
("https://smith.example.com/api-host", "https://smith.example.com"),
|
||||||
|
id="explicit_api_host_url_derives_dashboard_root",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"https://corp.example.com/langsmith/api-host",
|
||||||
|
None,
|
||||||
|
(
|
||||||
|
"https://corp.example.com/langsmith/api-host",
|
||||||
|
"https://corp.example.com/langsmith",
|
||||||
|
),
|
||||||
|
id="explicit_api_host_url_keeps_path_prefix_in_dashboard",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"http://localhost:8080",
|
||||||
|
None,
|
||||||
|
("http://localhost:8080", "http://localhost:8080"),
|
||||||
|
id="localhost_dashboard_is_the_same_origin",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"http://localhost:8080/api-host",
|
||||||
|
None,
|
||||||
|
("http://localhost:8080/api-host", "http://localhost:8080"),
|
||||||
|
id="localhost_api_host_dashboard_is_the_origin",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"https://eu.api.host.langchain.com",
|
||||||
|
None,
|
||||||
|
("https://eu.api.host.langchain.com", "https://eu.smith.langchain.com"),
|
||||||
|
id="regional_control_plane_maps_to_regional_dashboard",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_control_plane_endpoints_resolve(host_url, langsmith_endpoint, expected):
|
||||||
|
endpoints = ControlPlaneEndpoints.resolve(host_url, langsmith_endpoint)
|
||||||
|
|
||||||
|
assert (endpoints.control_plane_url, endpoints.dashboard_url) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("payload", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
{"resources": [{"id": "a"}, {"id": "b"}]},
|
||||||
|
[{"id": "a"}, {"id": "b"}],
|
||||||
|
id="list_returns_the_resources",
|
||||||
|
),
|
||||||
|
pytest.param({"resources": []}, [], id="empty_list"),
|
||||||
|
pytest.param({}, [], id="missing_key"),
|
||||||
|
pytest.param({"resources": None}, [], id="null_resources"),
|
||||||
|
pytest.param(
|
||||||
|
{"resources": ["nope", {"id": "a"}]}, [{"id": "a"}], id="skips_non_objects"
|
||||||
|
),
|
||||||
|
pytest.param([], [], id="unexpected_envelope"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_list_endpoints_return_resource_objects(payload, expected):
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
return httpx.Response(200, json=payload)
|
||||||
|
|
||||||
|
c = HostBackendClient(
|
||||||
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert c.list_deployments() == expected
|
||||||
|
|
||||||
|
|
||||||
|
def test_list_listeners_asks_for_a_full_page():
|
||||||
|
seen: dict = {}
|
||||||
|
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
seen["url"] = str(req.url)
|
||||||
|
return httpx.Response(200, json={"resources": [{"id": "listener-1"}]})
|
||||||
|
|
||||||
|
c = HostBackendClient(
|
||||||
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert c.list_listeners() == [{"id": "listener-1"}]
|
||||||
|
assert seen["url"] == "https://api.example.com/v2/listeners?limit=100"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("control_plane_url", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param("https://api.host.langchain.com", True, id="cloud"),
|
||||||
|
pytest.param("https://eu.api.host.langchain.com", True, id="cloud_region"),
|
||||||
|
pytest.param("https://dev.api.host.langchain.com", True, id="cloud_dev"),
|
||||||
|
pytest.param("https://smith.example.com/api-host", False, id="self_hosted"),
|
||||||
|
pytest.param(
|
||||||
|
"https://corp.example.com/langsmith/api-host",
|
||||||
|
False,
|
||||||
|
id="self_hosted_prefix",
|
||||||
|
),
|
||||||
|
pytest.param("http://localhost:8080/api-host", False, id="local"),
|
||||||
|
pytest.param(
|
||||||
|
"https://evil-api.host.langchain.com", False, id="lookalike_needs_a_dot"
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_is_cloud_recognises_the_managed_control_plane(control_plane_url, expected):
|
||||||
|
endpoints = ControlPlaneEndpoints.from_control_plane_url(control_plane_url)
|
||||||
|
|
||||||
|
assert endpoints.is_cloud is expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("call", "expected_params"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.list_deployments(name="agent"),
|
||||||
|
{"name": "agent"},
|
||||||
|
id="exact_name_filters_server_side",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.list_deployments(name_contains="age"),
|
||||||
|
{"name_contains": "age"},
|
||||||
|
id="substring_search_keeps_its_own_parameter",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.list_deployments(),
|
||||||
|
{},
|
||||||
|
id="no_filter_sends_no_parameters",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
lambda c: c.list_deployments(
|
||||||
|
name="agent", name_contains="agent", limit=100
|
||||||
|
),
|
||||||
|
{"name": "agent", "name_contains": "agent", "limit": "100"},
|
||||||
|
id="both_filters_travel_together_for_older_servers",
|
||||||
|
),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_list_deployments_sends_one_name_filter(call, expected_params):
|
||||||
|
seen: dict = {}
|
||||||
|
|
||||||
|
def handler(req: httpx.Request) -> httpx.Response:
|
||||||
|
seen.update(dict(req.url.params))
|
||||||
|
return httpx.Response(200, json={"resources": []})
|
||||||
|
|
||||||
|
call(
|
||||||
|
HostBackendClient(
|
||||||
|
"https://api.example.com", "key", transport=httpx.MockTransport(handler)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assert seen == expected_params
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("body", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
{"detail": "Source configuration error: bad listener"},
|
||||||
|
"Source configuration error: bad listener",
|
||||||
|
id="fastapi_detail_is_unwrapped",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
{"detail": {"loc": ["body"], "msg": "nope"}},
|
||||||
|
None,
|
||||||
|
id="a_structured_detail_is_left_alone",
|
||||||
|
),
|
||||||
|
pytest.param({"other": "shape"}, None, id="an_unknown_shape_is_left_alone"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_error_detail_is_readable(body, expected):
|
||||||
|
c = HostBackendClient(
|
||||||
|
"https://api.example.com",
|
||||||
|
"key",
|
||||||
|
transport=httpx.MockTransport(lambda req: httpx.Response(400, json=body)),
|
||||||
|
)
|
||||||
|
|
||||||
|
with pytest.raises(HostBackendError) as error:
|
||||||
|
c.get_deployment("dep-1")
|
||||||
|
|
||||||
|
assert error.value.detail == expected
|
||||||
|
if expected is not None:
|
||||||
|
assert error.value.message.endswith(expected)
|
||||||
|
|||||||
@@ -0,0 +1,71 @@
|
|||||||
|
import pytest
|
||||||
|
|
||||||
|
from langgraph_cli.image_reference import ImageReference
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("reference", "repository", "tag"),
|
||||||
|
[
|
||||||
|
pytest.param(
|
||||||
|
"registry.example.com/team/app:v1",
|
||||||
|
"registry.example.com/team/app",
|
||||||
|
"v1",
|
||||||
|
id="tag_after_last_slash",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"registry.example.com/team/app",
|
||||||
|
"registry.example.com/team/app",
|
||||||
|
None,
|
||||||
|
id="no_tag",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"localhost:5000/app",
|
||||||
|
"localhost:5000/app",
|
||||||
|
None,
|
||||||
|
id="registry_port_is_not_a_tag",
|
||||||
|
),
|
||||||
|
pytest.param(
|
||||||
|
"localhost:5000/app:latest",
|
||||||
|
"localhost:5000/app",
|
||||||
|
"latest",
|
||||||
|
id="registry_port_with_tag",
|
||||||
|
),
|
||||||
|
pytest.param("app:dev", "app", "dev", id="bare_name_with_tag"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_parse_splits_repository_and_tag(reference, repository, tag):
|
||||||
|
assert ImageReference.parse(reference) == ImageReference(repository, tag)
|
||||||
|
|
||||||
|
|
||||||
|
def test_with_tag_replaces_the_tag():
|
||||||
|
assert ImageReference("r/app", "v1").with_tag("v2") == ImageReference("r/app", "v2")
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("reference", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param(ImageReference("r/app", "v1"), "r/app:v1", id="tagged"),
|
||||||
|
pytest.param(ImageReference("r/app"), "r/app", id="untagged"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_str_renders_the_docker_reference(reference, expected):
|
||||||
|
assert str(reference) == expected
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
("repo_digest", "expected"),
|
||||||
|
[
|
||||||
|
pytest.param("localhost:5000/app@sha256:abc", True, id="same_repository"),
|
||||||
|
pytest.param("localhost:5000/app-2@sha256:abc", False, id="other_repository"),
|
||||||
|
pytest.param("mirror.example.com/app@sha256:abc", False, id="other_registry"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
def test_matches_digest_only_for_the_same_repository(repo_digest, expected):
|
||||||
|
assert ImageReference("localhost:5000/app", "v1").matches_digest(repo_digest) is (
|
||||||
|
expected
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_parse_rejects_a_digest_reference():
|
||||||
|
with pytest.raises(ValueError, match="digest"):
|
||||||
|
ImageReference.parse("registry.example.com/app@sha256:abc")
|
||||||
Generated
+124
-21
@@ -39,15 +39,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.13.0"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -217,9 +217,10 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.3.3"
|
version = "1.6.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "httpx" },
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
{ name = "langchain-protocol" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "langsmith" },
|
{ name = "langsmith" },
|
||||||
@@ -230,9 +231,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d3/ae/8b74458fc3850ec3d150eb9f45e857db129dafa801fb5cf173dfc9f8bbf3/langchain_core-1.3.3.tar.gz", hash = "sha256:fa510a5db8efdc0c6ff41c0939fb5c00a0183c11f6b84233e892e3227ff69182", size = 915041, upload-time = "2026-05-05T19:02:36.612Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/89/7b/406b4a8dd43dd01f69e04aafdee206809a2097134b2f944e12802eae7948/langchain_core-1.6.2.tar.gz", hash = "sha256:1ec6d3a98f7c8cdbb5bb0deff86e7ca37e16bf4f8f49f022d10723656c62352d", size = 1004390, upload-time = "2026-09-04T21:29:22.769Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/01/4771b7ab2af1d1aba5b710bd8f13d9225c609425214b357590a17b01be77/langchain_core-1.3.3-py3-none-any.whl", hash = "sha256:18aae8506f37da7f74398492279a7d6efcee4f8e23c4c41c7af080eeb7ef7bd1", size = 543857, upload-time = "2026-05-05T19:02:34.52Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/62/d3fb7c215cb2f237c3fe84880bf347a38deafef6033b6d5f1339ba8ca401/langchain_core-1.6.2-py3-none-any.whl", hash = "sha256:21e6c7cf097c68b777fd69ea00864f09bd9ca76ac73e3e3fa14e1ee366eb4711", size = 571690, upload-time = "2026-09-04T21:29:21.175Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -249,7 +250,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph"
|
name = "langgraph"
|
||||||
version = "1.1.6"
|
version = "1.2.11"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -259,27 +260,27 @@ dependencies = [
|
|||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "xxhash" },
|
{ name = "xxhash" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/e5/d3f72ead3c7f15769d5a9c07e373628f1fbaf6cbe7735694d7085859acf6/langgraph-1.1.6.tar.gz", hash = "sha256:1783f764b08a607e9f288dbcf6da61caeb0dd40b337e5c9fb8b412341fbc0b60", size = 549634, upload-time = "2026-04-03T19:01:32.561Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/56/0d/c8e7ee98896659e1b6555db0ab115a9ca899844744645d5d894032bab1d7/langgraph-1.2.11.tar.gz", hash = "sha256:9ecfe11e50d338b34b15cf4d8a442642de103e8ae6971320efba84e4542eb363", size = 725753, upload-time = "2026-08-11T14:00:36.945Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/e6/b36ecdb3ff4ba9a290708d514bae89ebbe2f554b6abbe4642acf3fddbe51/langgraph-1.1.6-py3-none-any.whl", hash = "sha256:fdbf5f54fa5a5a4c4b09b7b5e537f1b2fa283d2f0f610d3457ddeecb479458b9", size = 169755, upload-time = "2026-04-03T19:01:30.686Z" },
|
{ url = "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl", hash = "sha256:8bab70de7b2d00b5300fb289bcf38d8b241400f3184c1e95e8ce706fb0e8686b", size = 248854, upload-time = "2026-08-11T14:00:35.494Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint"
|
name = "langgraph-checkpoint"
|
||||||
version = "4.0.1"
|
version = "4.2.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
{ name = "ormsgpack" },
|
{ name = "ormsgpack" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b1/44/a8df45d1e8b4637e29789fa8bae1db022c953cc7ac80093cfc52e923547e/langgraph_checkpoint-4.0.1.tar.gz", hash = "sha256:b433123735df11ade28829e40ce25b9be614930cd50245ff2af60629234befd9", size = 158135, upload-time = "2026-02-27T21:06:16.092Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/dc/e1/089c4c9e0a2fec7f883f82ae8e6a727138d50074cfeb6644bc2d13b1019b/langgraph_checkpoint-4.2.0.tar.gz", hash = "sha256:51a593b6bee684b0818e5d6e58e28ab340c6db7794575056ce7bd1b746a84ed7", size = 180239, upload-time = "2026-08-07T20:05:03.756Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/65/4c/09a4a0c42f5d2fc38d6c4d67884788eff7fd2cfdf367fdf7033de908b4c0/langgraph_checkpoint-4.0.1-py3-none-any.whl", hash = "sha256:e3adcd7a0e0166f3b48b8cf508ce0ea366e7420b5a73aa81289888727769b034", size = 50453, upload-time = "2026-02-27T21:06:14.293Z" },
|
{ url = "https://files.pythonhosted.org/packages/05/71/3b475f09bd57d3a5649792c66353312b4432afd843f301739dfcebd157f0/langgraph_checkpoint-4.2.0-py3-none-any.whl", hash = "sha256:0547fd228935a0b758865de3a3d6d7a2537c308895d0f9ab092ce9151b5da942", size = 56833, upload-time = "2026-08-07T20:05:02.655Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-checkpoint-postgres"
|
name = "langgraph-checkpoint-postgres"
|
||||||
version = "3.0.5"
|
version = "3.1.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
@@ -287,35 +288,38 @@ dependencies = [
|
|||||||
{ name = "psycopg" },
|
{ name = "psycopg" },
|
||||||
{ name = "psycopg-pool" },
|
{ name = "psycopg-pool" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/95/7a/8f439966643d32111248a225e6cb33a182d07c90de780c4dbfc1e0377832/langgraph_checkpoint_postgres-3.0.5.tar.gz", hash = "sha256:a8fd7278a63f4f849b5cbc7884a15ca8f41e7d5f7467d0a66b31e8c24492f7eb", size = 127856, upload-time = "2026-03-18T21:25:29.785Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/06/92/1e8959f8cd1b56e672fde3227f6fd642be85af6c5fd662d73921074aa39d/langgraph_checkpoint_postgres-3.1.1.tar.gz", hash = "sha256:d320e147ddad8c374cd546df0b52b532dd54d0541dd9fd23fc738cbd5de76f41", size = 150413, upload-time = "2026-07-30T19:15:39.014Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/87/b0f98b33a67204bca9d5619bcd9574222f6b025cf3c125eedcec9a50ecbc/langgraph_checkpoint_postgres-3.0.5-py3-none-any.whl", hash = "sha256:86d7040a88fd70087eaafb72251d796696a0a2d856168f5c11ef620771411552", size = 42907, upload-time = "2026-03-18T21:25:28.75Z" },
|
{ url = "https://files.pythonhosted.org/packages/03/32/ba457698a48a0e18d786caa770033067049fbe36d6846f8e50f13b594b51/langgraph_checkpoint_postgres-3.1.1-py3-none-any.whl", hash = "sha256:6e353aecd8150de144fef8e51a49076f58b7d6830d4cf51392b7ad4d79832ba7", size = 50778, upload-time = "2026-07-30T19:15:37.405Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-prebuilt"
|
name = "langgraph-prebuilt"
|
||||||
version = "1.0.9"
|
version = "1.1.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
{ name = "langgraph-checkpoint" },
|
{ name = "langgraph-checkpoint" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/99/4c/06dac899f4945bedb0c3a1583c19484c2cc894114ea30d9a538dd270086e/langgraph_prebuilt-1.0.9.tar.gz", hash = "sha256:93de7512e9caade4b77ead92428f6215c521fdb71b8ffda8cd55f0ad814e64de", size = 165850, upload-time = "2026-04-03T14:06:37.721Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/29/66/ed9b93f56bc17ef22d551892f0ac2b225a97fe0fcf23a511b857f70d590b/langgraph_prebuilt-1.1.0.tar.gz", hash = "sha256:3c579cf6eed2d17f9c157c2d0fcaddcd8688524e7022d3b22b37a3bf4589d528", size = 178833, upload-time = "2026-05-12T03:37:49.332Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1d/a2/8368ac187b75e7f9d938ca075d34f116683f5cfc48d924029ee79aea147b/langgraph_prebuilt-1.0.9-py3-none-any.whl", hash = "sha256:776c8e3154a5aef5ad0e5bf3f263f2dcaab3983786cc20014b7f955d99d2d1b2", size = 35958, upload-time = "2026-04-03T14:06:36.58Z" },
|
{ url = "https://files.pythonhosted.org/packages/e9/43/3fe1a700b8490ed02679cdbbc8c915eb23a092faf496c9c1118abcd10be3/langgraph_prebuilt-1.1.0-py3-none-any.whl", hash = "sha256:51e311747d755b751d5c6b39b0c1446124d3a7643d2515017e6714b323508fc9", size = 41043, upload-time = "2026-05-12T03:37:48.007Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-sdk"
|
name = "langgraph-sdk"
|
||||||
version = "0.3.13"
|
version = "0.4.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
|
{ name = "langchain-core" },
|
||||||
|
{ name = "langchain-protocol" },
|
||||||
{ name = "orjson" },
|
{ name = "orjson" },
|
||||||
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/0e/db/77a45127dddcfea5e4256ba916182903e4c31dc4cfca305b8c386f0a9e53/langgraph_sdk-0.3.13.tar.gz", hash = "sha256:419ca5663eec3cec192ad194ac0647c0c826866b446073eb40f384f950986cd5", size = 196360, upload-time = "2026-04-07T20:34:18.766Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/3f/ae/91446c1fffa04a2dc1f81afbfb5bfff3590452891a72bd9098a656ab2657/langgraph_sdk-0.4.4.tar.gz", hash = "sha256:4e651ffa09de695681579396375377bdde23bedbc8e35b070e615cbd5af7da8b", size = 345789, upload-time = "2026-08-27T21:25:22.593Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fe/ef/64d64e9f8eea47ce7b939aa6da6863b674c8d418647813c20111645fcc62/langgraph_sdk-0.3.13-py3-none-any.whl", hash = "sha256:aee09e345c90775f6de9d6f4c7b847cfc652e49055c27a2aed0d981af2af3bd0", size = 96668, upload-time = "2026-04-07T20:34:17.866Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl", hash = "sha256:39afe416c91742925e6f8a93715f566d499b36e1b636b804a4ffe3190e4f4e64", size = 162270, upload-time = "2026-08-27T21:25:21.072Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -781,6 +785,105 @@ requires-dist = [
|
|||||||
{ name = "langgraph-checkpoint-postgres", specifier = ">=3.0.0" },
|
{ name = "langgraph-checkpoint-postgres", specifier = ">=3.0.0" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websockets"
|
||||||
|
version = "16.1.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/fd/6ec6c6d2850aea25b1b2aa9901a016980bb87d01e89b3eb00470b1b5d471/websockets-16.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ab59169ace05dcb49a1d4118f0bde139557adf45091bd85747e36bf5de984dd1", size = 179587, upload-time = "2026-07-17T22:49:38.959Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/d8/1d299d2dd34087db39831a34cc645ef8a6f89d78efada6983093513cd81c/websockets-16.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5e3b7d601f6f84156b08cc4a5e541c2b50ad7b36cfc302b657a12477c904a5df", size = 177272, upload-time = "2026-07-17T22:49:40.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cd2ca96a082a36964aca83e992f72abeb61b7306c1a6cba4c7d06a7b93750cac", size = 177530, upload-time = "2026-07-17T22:49:41.786Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f5d497865f05bb222cab7016c6034542e84e5f29f49c6fd3f4939cda7197b5b8", size = 187197, upload-time = "2026-07-17T22:49:43.658Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/13/88137fbaf726ebe29d62c1117fa11fa2bbb6209dc79d4ad738efbe36a2aa/websockets-16.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bae954c382e013d5ea5b190d2830526bfa45ad121c326da0049b8c769f185db6", size = 188433, upload-time = "2026-07-17T22:49:45.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/6d/46c2f2ce6751cb26f39293e1ecbf8544cb01321397cd476c2756b98c216d/websockets-16.1.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e09f753a169951eb4f28c2c774f71069304f66e7277e0f5a2892423599cfa854", size = 189868, upload-time = "2026-07-17T22:49:46.581Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/2b/170a9e8097636cfde4dc3c592b6e00b18a44a2f5407606d96ca542dd5838/websockets-16.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:024193f8551a2b0eafbdd160911012c4e6c228c28430c84433253299a9e42d6a", size = 189059, upload-time = "2026-07-17T22:49:47.972Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/48/f0d4ebc9ab4b473b8861b9e20fdb663d515d42f7befdf62cdb60fee7a1ec/websockets-16.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aabe464bfd13bd25f4821faf111da6fefdc389f870265a53105580e45b0a2e49", size = 187814, upload-time = "2026-07-17T22:49:49.344Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/ba/39a41d3ae8e72696a9492581900611c5a91e2b07563b0bcd2523adea9854/websockets-16.1.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a28fcbc9b6baf54a2e23f8655f308e4ccc6afdd7266f8fe7954f320dcda0f785", size = 185229, upload-time = "2026-07-17T22:49:50.787Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/36/ac15b604f850d1907f0a85ed721cefe47cd45034b3620069b829746cccbe/websockets-16.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79eace538c6a97e96d0d03d4f9d314f9677f5ed85a8a984992ffd90b13cb8a56", size = 187874, upload-time = "2026-07-17T22:49:52.228Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/f3/3fbd5d71d59299c3770faa5884d4f45070236ca5a35ab3a61830812c409a/websockets-16.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:496af849a472b531f758dbd4d61338f5000538cb1a7b3d20d9d32a264517f509", size = 186469, upload-time = "2026-07-17T22:49:53.776Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/fc/dd90349bba58af2a53ef2ddd9c32716c81eb6d59a0687939fff561860878/websockets-16.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5283810d2646741a0d8da2aa733d6aefa0545809afccb2a5d105a26bc45125f1", size = 188347, upload-time = "2026-07-17T22:49:55.202Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/f3/f73ba86427682da59b78c11d77ba56d5b801c32e84afe79b274bbd6a9bb2/websockets-16.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4e3b680b1e0a27457e727a0d572fd81dffa87b6dbf8b228ab57da64f7d85aead", size = 185903, upload-time = "2026-07-17T22:49:56.75Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/7c/f95eb20e80104173b3a0a092291f89ea4047ef6e608e0a57ca06eb14eecb/websockets-16.1.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69159730a823dde3ea8d08783e8d47ef135a6d7e8d44eb127e32b321c9db8e3e", size = 186855, upload-time = "2026-07-17T22:49:58.467Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/35/dd875b3e050ff232d60fa377707f890e369f74d134f1be32e8f68879747c/websockets-16.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ed5bb271084b46530ee2ddc0410537a9961152c5ccba2fc98c5276d992ccba87", size = 187140, upload-time = "2026-07-17T22:50:00.016Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/dc/5cbfcb41824502f6af93b8f3943a4d06c67c23c7d2e31eb18748c4a5b2a7/websockets-16.1.1-cp313-cp313-win32.whl", hash = "sha256:cfb70b4eb56cac4da0a83588f3ad50d46beb0690391082f3d4e2d488c70b68ea", size = 179928, upload-time = "2026-07-17T22:50:01.685Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/c1/71e5deb5b7f8f226997ab64908c184ac3105c0155ce2d486f318e5dd08a8/websockets-16.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9531d9cbeac99af6f038fb1bc351403531f7d634a2c2e10e2f7c854c6ed5b68", size = 180242, upload-time = "2026-07-17T22:50:03.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/a2/ba78a164eeea4620df4a4df4bd2ed6017438c4655cc0f36f2c0bc0432355/websockets-16.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:443aefe96b7fdb132e2a70806cca1f2af49bb3f28e47abcd7c2e9dcf4d8fa1b8", size = 179635, upload-time = "2026-07-17T22:50:05.001Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/08/d26d7a7628cd4ac34cbbdb63ac80914ca842ed8e42938c40a53567806df3/websockets-16.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6456ff333092d509127d75a638cb411afae8ff17f092635015d1902efec8a293", size = 177320, upload-time = "2026-07-17T22:50:06.427Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/45/ebec83e6269536aa5932533c67b0af5c781f3e73fdbcd68672dcf43f4f44/websockets-16.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fce6c48559c86d1ac3632ccb1bebc7d5442fbe79bd9bb0e40379ee54be2a4051", size = 177544, upload-time = "2026-07-17T22:50:07.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/d5/abc614d2297f6c1c3e01e61260364457a47c25cc1cf6a879038902bc6aa8/websockets-16.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:92b820d345f7a3fc7b8163949ee92df910f290c3fc517b3d5301c78065adafe1", size = 187270, upload-time = "2026-07-17T22:50:09.275Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/71/4c99af3b87dff1b2927981f6876607d4acb45338c665242168d3982f7758/websockets-16.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a606d9c24035242a3e256e9d5b77ed9cd6bccfcb7cf993e5ca3c0f6f68fb6a7", size = 188509, upload-time = "2026-07-17T22:50:10.722Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/b4/5c8ca14b0df7eb84ed0524165c5359150210140817a3312aee57bf62a1cf/websockets-16.1.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:414e596c75f74e0994084694189d7dc9229fb278e33064d6784b73ffbba3ca31", size = 189882, upload-time = "2026-07-17T22:50:12.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/c1/bedfba9e70557129cb8083748d167bdcc01483dedf0f0df143676df05cbe/websockets-16.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:536676848fc5961aca9d20389951f59169508f765637a172403dc5434d722fa0", size = 189114, upload-time = "2026-07-17T22:50:13.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/09/aa835b2787835aebd839114be5de51b797cb480b63ba42b26d34dfe147cb/websockets-16.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97fd3a0e8b53efa41970ac1dff3d8cf0d2884cadeb4caaf95db7ad1526926ee3", size = 187861, upload-time = "2026-07-17T22:50:15.179Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/26/f6408330694dbc9830857d9d23bc14ac4f6875127a480cfdda8d5ca21198/websockets-16.1.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7b1b19636af86a3c7995d4d028dbe376f39b4bf31541146f9c123582a6c94562", size = 185286, upload-time = "2026-07-17T22:50:16.741Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/9a/e0675e70dd8a80762cf35bb18799d3f290a4890ffe6439bc51d222796083/websockets-16.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:41c8e77f17294c0ac18008a7309b99b34ee72247ef10b6dff4c3f8b5ac29896b", size = 187935, upload-time = "2026-07-17T22:50:18.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/c1/3234cfb86afde01b81e9bddcc6e534c440975d60a13991259e833069ab3e/websockets-16.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9f63bcef7f4b02b06b35fc01c93b96c43b5e88e1e8868676caacf493d5a31f3a", size = 186444, upload-time = "2026-07-17T22:50:19.67Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/87/9c15206e1d778923d8daa9657de07aa62ea815e13448319c98458c37b281/websockets-16.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dab9eb87869da2d6ed3af3f3adf28414baae6ec9d4df355ffc18889132f3436c", size = 188409, upload-time = "2026-07-17T22:50:21.28Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/00/cf5de5c67676de2d3eef8b2a518f168f6796595447a5b7161ba0d012915c/websockets-16.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:43e3a9fdd7cbf7ba6040c31fae0faf84ca1474fef777c4e37912f1540f854499", size = 185958, upload-time = "2026-07-17T22:50:22.719Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/c0/731b6ddede2e4136912ec4cff2cffbda35af73546be4762c3d7bd3bd79af/websockets-16.1.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:056ae37939ed7e9974f364f5864e76e49182622d8f9751ac1903c0d09b013985", size = 186911, upload-time = "2026-07-17T22:50:24.108Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/7f/39c634472c4469a24a7c09cecddffb08fac6d0e74f73881a94ee8a40a196/websockets-16.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0eadbbf2c30f01efa58e1f110eb6fa293261f6b0b1aa38f7f48707107690af9", size = 187204, upload-time = "2026-07-17T22:50:25.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/89/9667c256c256dafcc62d21328ce7a40067da857969b68ee9af375b0aaf72/websockets-16.1.1-cp314-cp314-win32.whl", hash = "sha256:195c978b065fa40910582464f99d6b15c8b314c68e0546549a55ed83f4735328", size = 179603, upload-time = "2026-07-17T22:50:27.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/dd/1c099d6c0fc5deb6b46ccdbb6981fdb4b12c917869cb3952408409dc18db/websockets-16.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:4e8d01cc3bcae7bbf8167f944aeafefed590fae5693552bba9794a9df68371cc", size = 179948, upload-time = "2026-07-17T22:50:28.521Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/25/9956b2d5e0529d5d23924f21bba1440d4c5c88a562e4f08550871ffa97a7/websockets-16.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0ffd3031ea8bda8d61762e84220186105ba3b748b3c8da2ae4f7816fac03e573", size = 179963, upload-time = "2026-07-17T22:50:29.982Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/06/55ffc976c488b6aee9ea05761ff7c4e88e7c1fd82818c8ca7b556ad2f90c/websockets-16.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:84a2cef8deffbd9ab8ee0ea546a2a6a7030c28f44e6cdd4547dbfeb489eb8999", size = 177497, upload-time = "2026-07-17T22:50:31.396Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3df13f73af9b3b38ab1195eb299ecb67a4330c911c97ae04043ff74085728abe", size = 177698, upload-time = "2026-07-17T22:50:32.829Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:23253dd5bcae3f9aaee0a1d30967a8dbd52e5d3cff93a2e5b84df57b77d4750d", size = 187561, upload-time = "2026-07-17T22:50:34.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/94/c3f330851806b9b02138b774d593478323e73c99238681b4b93efe64e02d/websockets-16.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1c5705e314449e3308872fe084b8571ce078ee4fc55a98a769bdefe5917392", size = 188732, upload-time = "2026-07-17T22:50:36.088Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/f2/eb2c450f052de334ae33cf200ece6e87b0e14d186807074e4eb1cd2cdea2/websockets-16.1.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69e52d175a0a7d1e13b4b67ad41c560b7d98e8c6f6126eb0bda496c784faf8c7", size = 190872, upload-time = "2026-07-17T22:50:38.008Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/31/2ac8cecf3a74f7fed9132129fc3d90b3998a1554570c11a69b2a8c20332d/websockets-16.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1f79c89b5eb034d1722938a891916582f8f7f503f58ca22518a63c3f2cd18499", size = 189305, upload-time = "2026-07-17T22:50:39.53Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/cf/8ab19650d3c0d4562c92e70ab47c257c4aa5c6a713ed87fe63766b31fefc/websockets-16.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39f2a024af5c345ffe8fcf1ee18c049c024c94df393bb09b044a6917c77bde43", size = 188033, upload-time = "2026-07-17T22:50:40.912Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/d7/a49a38a6127a4acb134fb1912b215d900cc657605cff32445bf519f3acc4/websockets-16.1.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:952303a7318d4cbe1011400839bb2051c9f84fa0a35923267f5daba34b15d458", size = 185748, upload-time = "2026-07-17T22:50:42.559Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/3e/ad1fa40388c7f2e0bb2c7930d0090b6c5498594bd1cdaec18864df3d9e97/websockets-16.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:249116b4a76063d930a46391ad56e135c286e4562a18309029fc2c73f4ed4c62", size = 188285, upload-time = "2026-07-17T22:50:43.974Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/b8/d5db28ca264b9104f82196f92dc8843e35fd391f763d42e4ad358f5bc97e/websockets-16.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:61922544a0587a13fd3f53e4c0e5e606510c7b0d9d22c8444e5fae22a06b38cb", size = 186777, upload-time = "2026-07-17T22:50:45.474Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/9c/726cb39d0cc43ae848dce4aa2acb04eecc6738b1264ec6d700bf6bcfb9f8/websockets-16.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:46dcaa042cd1de6c59e7d9269fa63ff7572b6df40510600b678f0826b3c7af51", size = 188682, upload-time = "2026-07-17T22:50:46.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/c7/1168704de8c2dd483edabe4a22cbe4465dd8be8dd95561d214f9fe092871/websockets-16.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:38565aca3e01ea8734e578fb2118dade0ecb0250533f29e22b8d1a7a196cf4d0", size = 186377, upload-time = "2026-07-17T22:50:48.413Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/40/f9ff2d630ffce4e7dfea0b2288e1caf9ebbf9ff8a9ec9396136ce8b94935/websockets-16.1.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:42f599f4d48c7e1a3338fdaac3acd075be3b3cf02d4b274f3bf2767aedd3d217", size = 187148, upload-time = "2026-07-17T22:50:49.845Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/71/e177c8299f78d7cbe2d14df228643c10c70c0e86e108e092056bbcc16e46/websockets-16.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcc04fedf83effaeb9cce98abc9469bb1b42ef85f03e01c8c1f4438ef7555737", size = 187578, upload-time = "2026-07-17T22:50:51.619Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/b2/b6987faf330f5af5c787a2610124c2e8403d51724f9001ec4fff6311fe7a/websockets-16.1.1-cp314-cp314t-win32.whl", hash = "sha256:8483c2096363120eea8b07c06ae7304d520f686665fffd4811fad423930a65d7", size = 179729, upload-time = "2026-07-17T22:50:53.269Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/6e/fbac6ed878dd362fbad7d415fa4f84d38e3e33fed8cde45c64e783acf826/websockets-16.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bcce07e23e5769375158f5efdcdafa8d5cd014b93c6683865b840ed65b96f231", size = 180072, upload-time = "2026-07-17T22:50:54.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xxhash"
|
name = "xxhash"
|
||||||
version = "3.6.0"
|
version = "3.6.0"
|
||||||
|
|||||||
Generated
+115
-12
@@ -13,15 +13,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.13.0"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -191,9 +191,10 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langchain-core"
|
name = "langchain-core"
|
||||||
version = "1.4.0"
|
version = "1.6.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
{ name = "httpx" },
|
||||||
{ name = "jsonpatch" },
|
{ name = "jsonpatch" },
|
||||||
{ name = "langchain-protocol" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "langsmith" },
|
{ name = "langsmith" },
|
||||||
@@ -204,9 +205,9 @@ dependencies = [
|
|||||||
{ name = "typing-extensions" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/59/de/679a53472c25860837e32c0442c962fa86e95317a36460e2c9d5c91b17c2/langchain_core-1.4.0.tar.gz", hash = "sha256:1dc341eed802ed9c117c0df3923c991e5e9e226571e5725c194eeb5bd93d1a7f", size = 920260, upload-time = "2026-05-11T18:42:35.919Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/89/7b/406b4a8dd43dd01f69e04aafdee206809a2097134b2f944e12802eae7948/langchain_core-1.6.2.tar.gz", hash = "sha256:1ec6d3a98f7c8cdbb5bb0deff86e7ca37e16bf4f8f49f022d10723656c62352d", size = 1004390, upload-time = "2026-09-04T21:29:22.769Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0f/1a/86c38c27b81913a1c6c12448cab55defb5a1097c7dc9a4cea83f55477a2d/langchain_core-1.4.0-py3-none-any.whl", hash = "sha256:23cbbdb46e38ddd1dd5247e6167e96013eae74bea4c5949c550809970a9e565c", size = 548120, upload-time = "2026-05-11T18:42:33.992Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/62/d3fb7c215cb2f237c3fe84880bf347a38deafef6033b6d5f1339ba8ca401/langchain_core-1.6.2-py3-none-any.whl", hash = "sha256:21e6c7cf097c68b777fd69ea00864f09bd9ca76ac73e3e3fa14e1ee366eb4711", size = 571690, upload-time = "2026-09-04T21:29:21.175Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -223,7 +224,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph"
|
name = "langgraph"
|
||||||
version = "1.2.2"
|
version = "1.2.11"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core" },
|
{ name = "langchain-core" },
|
||||||
@@ -233,9 +234,9 @@ dependencies = [
|
|||||||
{ name = "pydantic" },
|
{ name = "pydantic" },
|
||||||
{ name = "xxhash" },
|
{ name = "xxhash" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e6/5a/ffc12434ee8aecab830d58b4d204ddea45073eae7639c963310f671a5bf5/langgraph-1.2.2.tar.gz", hash = "sha256:f54a98458976b3ff0774683867df125fb52d8dbedeb2441d0b0656a51331cee5", size = 695730, upload-time = "2026-05-26T18:07:28.49Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/56/0d/c8e7ee98896659e1b6555db0ab115a9ca899844744645d5d894032bab1d7/langgraph-1.2.11.tar.gz", hash = "sha256:9ecfe11e50d338b34b15cf4d8a442642de103e8ae6971320efba84e4542eb363", size = 725753, upload-time = "2026-08-11T14:00:36.945Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/9b/b08d578bba73e25351152dfd3d6d21e81210a5fff1b6f26e56f33197c8f5/langgraph-1.2.2-py3-none-any.whl", hash = "sha256:0a851bf4ba5939c5474a2fd57e6b439b5315283e254e42943bd392c2d71a5e03", size = 236376, upload-time = "2026-05-26T18:07:26.577Z" },
|
{ url = "https://files.pythonhosted.org/packages/0a/7f/c5c30e4be99ff821029c7ac872a480676bb179c9f3df85ea3f38d13f86d4/langgraph-1.2.11-py3-none-any.whl", hash = "sha256:8bab70de7b2d00b5300fb289bcf38d8b241400f3184c1e95e8ce706fb0e8686b", size = 248854, upload-time = "2026-08-11T14:00:35.494Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -266,15 +267,18 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-sdk"
|
name = "langgraph-sdk"
|
||||||
version = "0.3.15"
|
version = "0.4.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "httpx" },
|
{ name = "httpx" },
|
||||||
|
{ name = "langchain-core" },
|
||||||
|
{ name = "langchain-protocol" },
|
||||||
{ name = "orjson" },
|
{ name = "orjson" },
|
||||||
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/66/af/cdd4d6f3c05b3c1112ed3f12ef830faf15951b21d22cbc622a4becbbe25c/langgraph_sdk-0.3.15.tar.gz", hash = "sha256:29e805003d2c6e296823dd71992610976fd0428cefaa8b3304fd91f2247037de", size = 201924, upload-time = "2026-05-22T16:54:27.678Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/3f/ae/91446c1fffa04a2dc1f81afbfb5bfff3590452891a72bd9098a656ab2657/langgraph_sdk-0.4.4.tar.gz", hash = "sha256:4e651ffa09de695681579396375377bdde23bedbc8e35b070e615cbd5af7da8b", size = 345789, upload-time = "2026-08-27T21:25:22.593Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/be/a5/0196d9c05749c25bc198e4909d68c998bc3120297e14944921baf2f4c384/langgraph_sdk-0.3.15-py3-none-any.whl", hash = "sha256:3838773acf7456d158165385d49f48f1e856f28b56ccd99ea139a8f27004815d", size = 98166, upload-time = "2026-05-22T16:54:26.013Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl", hash = "sha256:39afe416c91742925e6f8a93715f566d499b36e1b636b804a4ffe3190e4f4e64", size = 162270, upload-time = "2026-08-27T21:25:21.072Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -775,6 +779,105 @@ wheels = [
|
|||||||
{ url = "https://files.pythonhosted.org/packages/44/e7/3937b9a9d6745b94dbe7b86531e098db8c53b77c8d07df7daa9577a47b8e/uuid_utils-0.16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:680799a9ade01d69c53cb9d41392ced24919d4f600bfab5060b61fca37510097", size = 178508, upload-time = "2026-05-19T07:43:43.774Z" },
|
{ url = "https://files.pythonhosted.org/packages/44/e7/3937b9a9d6745b94dbe7b86531e098db8c53b77c8d07df7daa9577a47b8e/uuid_utils-0.16.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:680799a9ade01d69c53cb9d41392ced24919d4f600bfab5060b61fca37510097", size = 178508, upload-time = "2026-05-19T07:43:43.774Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "websockets"
|
||||||
|
version = "16.1.1"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/21/f7/bc3a25c5ec26ce62ce487690becc2f3710bbc7b33338f005ad390db0b986/websockets-16.1.1.tar.gz", hash = "sha256:db234eda965dcce15df96bb9709f587cd87d4d52aaf0e80e2f34ec04c7670c57", size = 182204, upload-time = "2026-07-17T22:51:05.858Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2b/03/47debfe28e9d6d354be5d777b67fd44c359b9eb299a5d103500bd7cc3e37/websockets-16.1.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:d0fcf657e9f13ff4b177960ab2200237b12994232dfb6df16f1cfe1d4339f93c", size = 179566, upload-time = "2026-07-17T22:48:49.596Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/72/93/31efa1ed78c17e5cfc229fd449e3966e1b9cc15753204cd585cc8dd01f4a/websockets-16.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b852788aa51764e2d8e4cf5493d559326bcae5e38d16ba25ffa322b034df272a", size = 177250, upload-time = "2026-07-17T22:48:50.942Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/4a/542378ab3972b0c1cf1df3df3eff9591cea0d30c58c3aa3c4ddbc244e787/websockets-16.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1427fb4cf0d72f66333e2cacc3ff5f575bf2d7008166ce991a4a470b21d51a22", size = 177528, upload-time = "2026-07-17T22:48:52.59Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/d9/162321f63c7eed558e9e1798ed7a1e34a4f6dab51f35419e4ed7a4907979/websockets-16.1.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:da4ca1a9d72f9030b3146b8d7022719a9f3d478f61efe6f7dd51d243f61c51b2", size = 186859, upload-time = "2026-07-17T22:48:53.915Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/de/09/87df740f7430ce564bd52402e9c9458d4d0459cc7d2ee29e530c8204851b/websockets-16.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:86d7f0f8bdb25d2c632b72527325e4776430fd5bc61b9118de4e2b8ddb5f5b01", size = 188095, upload-time = "2026-07-17T22:48:55.384Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d2/12/3d2703af7cc095f3c81904c92208cc1ae79affbc67376944b50ee9301f73/websockets-16.1.1-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7dfcad78ea1492ee3a9ec765cb7f51bbc17d477107aaf6b22abf7b2558d1c5a0", size = 191385, upload-time = "2026-07-17T22:48:56.742Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/69/986aa0234a964a00f5149cfc46e136e96c8faad1c783474550f40d31aef4/websockets-16.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fb9a0a6dc3d1b3986cb88091b6899f0396651e0f74e2c9766ab8d6ffc3842e29", size = 188653, upload-time = "2026-07-17T22:48:58.134Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/6b/10f9d03e3970a69ba67bd3b46b87a929b586d0300fadbfe14f57c1f85490/websockets-16.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:29dfa8114c4a620c69591c5973860f768eac29d3fd6904f37f34266cb219c512", size = 187426, upload-time = "2026-07-17T22:48:59.515Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/56/db/bb3aad62bf63d8bb3f0634b2eabffcfb3677a34bd19492110ff6869cf703/websockets-16.1.1-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6ff9417c0ada4d0f7d212f928303e5579bdf3ace4c802fa4afabb30995da58c3", size = 184882, upload-time = "2026-07-17T22:49:00.916Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6c/4c/c09a2ea9bfbeccce52fdc383e5f28af4bc8843338aabac28c81489af6120/websockets-16.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fe0b50da2d84535fb4f7b4bfa951280f97ce3d558a0443b541166d609e67b57", size = 187584, upload-time = "2026-07-17T22:49:02.283Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c7/8b/31bb4eb4d9eaacf1fdd39d115772a8aeaedfc19b5dc262e57ffbc8a9d42c/websockets-16.1.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:34420aaa64440ebd51ac72ca8a45ef4626429438c9b02e633ae412ed43f925d3", size = 186174, upload-time = "2026-07-17T22:49:03.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2f/e4/dc02d725610a1ad49e193ef91a548194d71bdc6cdf27da83067dd1f73995/websockets-16.1.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a6a61aff018180c9c50b7b0da33bfd29d378af3497429c95006c589a23a11648", size = 187986, upload-time = "2026-07-17T22:49:05.553Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e0/73/30ed84c8bfd14c73d4af29d5ed9323c3073b48e0b7b23b67070f4e7fd59b/websockets-16.1.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:04fd29a0e2fe9414a95b00e92c67ae51bf900c50c0f8a4b2dafdad621f49ea1d", size = 185565, upload-time = "2026-07-17T22:49:06.959Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7d/d3/4be8d4959f51e31b4f8fc0ece12b45bd3b6c0d15ea23b9990d9c11fc805f/websockets-16.1.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:5c31aa7e39ee3e8a358573257f1c0bb5c52430d1b637030dd9c8cc2c282926be", size = 186598, upload-time = "2026-07-17T22:49:08.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/fa/abb38597a52d84ed9cfacadc7a0c6f2db282c0ab23cdf72b58a666a21227/websockets-16.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:d14bfb217eb4701e850f1525c9d29d79c44794cdf1c299ead25f39f8c78dea81", size = 186834, upload-time = "2026-07-17T22:49:09.766Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/59/80/1119ad08a228b90c4eb77fbe48df7836731a605f5f881ba701ca826a4a65/websockets-16.1.1-cp311-cp311-win32.whl", hash = "sha256:2e28e602bb13da44fbe518c1781a88e3b9d4c3d48d02c9bad83e546164336f57", size = 179940, upload-time = "2026-07-17T22:49:11.196Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/71/b2/e511c1c6f64a95c2f3fc54bffda0e14eaa7e9442be605c29270f7589b918/websockets-16.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:7421fad442de870a8cbf2287d1cad7e706ece0dbfeba5e911df132cbdc1cb56a", size = 180239, upload-time = "2026-07-17T22:49:12.519Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/9d/681cda21c9eee743203a6cb79b9d3d05adad9aa60ec660c6c9bf4dd619ca/websockets-16.1.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:cc97814dfb786a83b6e2dc2e79351e1b83e6d715647d6887fcabd83026417a00", size = 179600, upload-time = "2026-07-17T22:49:13.92Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fb/8d/6195a88b45e8d2a8f745fc2046e36f885a3c9763e6767d2c46229bf9510c/websockets-16.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e047dc87ef7ca50f4d309bf775ad4a71711c58556d75d7bd0604b2317f43e94b", size = 177272, upload-time = "2026-07-17T22:49:15.453Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/e3/fe2d498c64dea0095c9a9f9a351af4cd6eef31b618395582bc1f38ba45ff/websockets-16.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:01fbdcbac298efe19360b94bc0039c8f746f0220ba570f327577bfee81059175", size = 177542, upload-time = "2026-07-17T22:49:16.875Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/fe/ed/f1831681fce0e3242346e5458486003c5f124ed69e5e0b847fd029db4973/websockets-16.1.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f62863e8a00a6d33c3d6566ec0b89f23787b747ffe0c3bc71ec0e76b82c94b1", size = 187137, upload-time = "2026-07-17T22:49:18.323Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6f/79/4ff9dcc1bb46f6b4c536936dde1fd60f9b564f3304307274db97f4c9496d/websockets-16.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8087e82f842609734c9b5a1330464f8e94e346ba0e18c832c08bafa4b0d63c15", size = 188374, upload-time = "2026-07-17T22:49:19.65Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/c3/5c49b6efb36cab733d23773f6de575e1dba65736ead17d5d2b2a1daef779/websockets-16.1.1-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2bb5d041a8307d2e18782e7ce777f6fdb1e8c2f5d09291484b18c294b789d9aa", size = 191155, upload-time = "2026-07-17T22:49:21.331Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6e/f6/56ccceda3a4838d18f1d40821480da4775397e8b1eecf4031e20c50e2e90/websockets-16.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1db4de4a0e95673f7545d393c49eeb0c2f18ac1ef93073218c79d5cdb2ee75ab", size = 189011, upload-time = "2026-07-17T22:49:22.889Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/86/d6/ad5286241a2bce1107e2798d3bfbd62cf79aee167bdb654f8cb1e9dbf949/websockets-16.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:f17dbe07eb3ea7f99e4df9b7e0efefe80fbf30d37a8cc4d561a0aed310bc8847", size = 187766, upload-time = "2026-07-17T22:49:24.339Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bc/67/d65c970b7e347fdca69479beb7811c2060529956730a7a4e3ae7c66b0e31/websockets-16.1.1-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b57693728576d84ede0a77987ab16881b783d2cd9f1dc180a8fbbc3f79c4428", size = 185173, upload-time = "2026-07-17T22:49:25.743Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/1d/5b/14af3cd4ee69d8ea9baca58f3dc3cfb1ba78332a347fd478cb096549d60e/websockets-16.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2a636ff1e7a5c4edf71ef0e79adae7f25dba93b4fcbe3dc958733477ffeb0eaf", size = 187809, upload-time = "2026-07-17T22:49:27.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/7b/11/be301710d70de97e3e7b3586e6d492c9c06d6a61bf1c2202c36cf0c75607/websockets-16.1.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d6bec75c290fe484a8ba4cacdf838501e17c06ecfbbf31eede81a9e431bd7751", size = 186412, upload-time = "2026-07-17T22:49:28.611Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/db/07/fe1435bf6fe738a3d3b54dbe0c18dabf12cba4d909ac8b58b539ce27c1f4/websockets-16.1.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:54509b8e92fee4453e152b7558ddef37ce9705a044922f2095a6105e3f80c96f", size = 188290, upload-time = "2026-07-17T22:49:29.965Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8a/0a/81f394aff8efcbb01208c1ced77df0a3c7fcce584a88c7273663697946c2/websockets-16.1.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:f0aa4aad3b1b69ad3fd85a0fd0952ec64331c762bd77ec51cc814170873890b2", size = 185844, upload-time = "2026-07-17T22:49:31.447Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/39/5c/dd485b995473f415510251fe9bd708f2d24458f439fce958daf8d66dc7c6/websockets-16.1.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:42290eb6db4ccaca7012656738214f8514082fb6fa40cdeb61bb9a471b52e383", size = 186823, upload-time = "2026-07-17T22:49:33.104Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9d/0b/f78de76ff446f1e66af12b43c48a35f31744de93cfdec2f4ea67d5d7bbf1/websockets-16.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:53260c8930da5771cec89439bff99c20c8cb03ddb9588b980697355a83cd4bd3", size = 187102, upload-time = "2026-07-17T22:49:34.616Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/a1/4cf892007778eaf84ad162bfc98046e0ed89b63ac55949e3236626b2a23f/websockets-16.1.1-cp312-cp312-win32.whl", hash = "sha256:1d27fa8462ad6a1cb36206a3d0640b2333340def181fae11ed7f9adeaa5c0747", size = 179943, upload-time = "2026-07-17T22:49:36.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d9/de/6abe251d28c3a3f217096575400b27750b18e0b1d2fff3a2a239960fea07/websockets-16.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:b436f6ec4fc3a6b4237c84d3f83170ed2b40bb584222f0ac47a0c8a5921980c7", size = 180243, upload-time = "2026-07-17T22:49:37.626Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ce/fd/6ec6c6d2850aea25b1b2aa9901a016980bb87d01e89b3eb00470b1b5d471/websockets-16.1.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ab59169ace05dcb49a1d4118f0bde139557adf45091bd85747e36bf5de984dd1", size = 179587, upload-time = "2026-07-17T22:49:38.959Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/5f/d8/1d299d2dd34087db39831a34cc645ef8a6f89d78efada6983093513cd81c/websockets-16.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5e3b7d601f6f84156b08cc4a5e541c2b50ad7b36cfc302b657a12477c904a5df", size = 177272, upload-time = "2026-07-17T22:49:40.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3d/86/0a70d3ae2f0f2256bb41302d9804dbca65d4360281e7feb3e1f94102ac46/websockets-16.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cd2ca96a082a36964aca83e992f72abeb61b7306c1a6cba4c7d06a7b93750cac", size = 177530, upload-time = "2026-07-17T22:49:41.786Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/c2/c676c69444d9db448b3f0a55a98dcc534affce0bce961d9d2f0b8499b10a/websockets-16.1.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f5d497865f05bb222cab7016c6034542e84e5f29f49c6fd3f4939cda7197b5b8", size = 187197, upload-time = "2026-07-17T22:49:43.658Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0b/13/88137fbaf726ebe29d62c1117fa11fa2bbb6209dc79d4ad738efbe36a2aa/websockets-16.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bae954c382e013d5ea5b190d2830526bfa45ad121c326da0049b8c769f185db6", size = 188433, upload-time = "2026-07-17T22:49:45.147Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/6d/46c2f2ce6751cb26f39293e1ecbf8544cb01321397cd476c2756b98c216d/websockets-16.1.1-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e09f753a169951eb4f28c2c774f71069304f66e7277e0f5a2892423599cfa854", size = 189868, upload-time = "2026-07-17T22:49:46.581Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/29/2b/170a9e8097636cfde4dc3c592b6e00b18a44a2f5407606d96ca542dd5838/websockets-16.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:024193f8551a2b0eafbdd160911012c4e6c228c28430c84433253299a9e42d6a", size = 189059, upload-time = "2026-07-17T22:49:47.972Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a7/48/f0d4ebc9ab4b473b8861b9e20fdb663d515d42f7befdf62cdb60fee7a1ec/websockets-16.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:aabe464bfd13bd25f4821faf111da6fefdc389f870265a53105580e45b0a2e49", size = 187814, upload-time = "2026-07-17T22:49:49.344Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d5/ba/39a41d3ae8e72696a9492581900611c5a91e2b07563b0bcd2523adea9854/websockets-16.1.1-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a28fcbc9b6baf54a2e23f8655f308e4ccc6afdd7266f8fe7954f320dcda0f785", size = 185229, upload-time = "2026-07-17T22:49:50.787Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/3c/36/ac15b604f850d1907f0a85ed721cefe47cd45034b3620069b829746cccbe/websockets-16.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:79eace538c6a97e96d0d03d4f9d314f9677f5ed85a8a984992ffd90b13cb8a56", size = 187874, upload-time = "2026-07-17T22:49:52.228Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a8/f3/3fbd5d71d59299c3770faa5884d4f45070236ca5a35ab3a61830812c409a/websockets-16.1.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:496af849a472b531f758dbd4d61338f5000538cb1a7b3d20d9d32a264517f509", size = 186469, upload-time = "2026-07-17T22:49:53.776Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b4/fc/dd90349bba58af2a53ef2ddd9c32716c81eb6d59a0687939fff561860878/websockets-16.1.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5283810d2646741a0d8da2aa733d6aefa0545809afccb2a5d105a26bc45125f1", size = 188347, upload-time = "2026-07-17T22:49:55.202Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/4c/f3/f73ba86427682da59b78c11d77ba56d5b801c32e84afe79b274bbd6a9bb2/websockets-16.1.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4e3b680b1e0a27457e727a0d572fd81dffa87b6dbf8b228ab57da64f7d85aead", size = 185903, upload-time = "2026-07-17T22:49:56.75Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/34/7c/f95eb20e80104173b3a0a092291f89ea4047ef6e608e0a57ca06eb14eecb/websockets-16.1.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:69159730a823dde3ea8d08783e8d47ef135a6d7e8d44eb127e32b321c9db8e3e", size = 186855, upload-time = "2026-07-17T22:49:58.467Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/35/dd875b3e050ff232d60fa377707f890e369f74d134f1be32e8f68879747c/websockets-16.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ed5bb271084b46530ee2ddc0410537a9961152c5ccba2fc98c5276d992ccba87", size = 187140, upload-time = "2026-07-17T22:50:00.016Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e8/dc/5cbfcb41824502f6af93b8f3943a4d06c67c23c7d2e31eb18748c4a5b2a7/websockets-16.1.1-cp313-cp313-win32.whl", hash = "sha256:cfb70b4eb56cac4da0a83588f3ad50d46beb0690391082f3d4e2d488c70b68ea", size = 179928, upload-time = "2026-07-17T22:50:01.685Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b0/c1/71e5deb5b7f8f226997ab64908c184ac3105c0155ce2d486f318e5dd08a8/websockets-16.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:d9531d9cbeac99af6f038fb1bc351403531f7d634a2c2e10e2f7c854c6ed5b68", size = 180242, upload-time = "2026-07-17T22:50:03.117Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/73/a2/ba78a164eeea4620df4a4df4bd2ed6017438c4655cc0f36f2c0bc0432355/websockets-16.1.1-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:443aefe96b7fdb132e2a70806cca1f2af49bb3f28e47abcd7c2e9dcf4d8fa1b8", size = 179635, upload-time = "2026-07-17T22:50:05.001Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b9/08/d26d7a7628cd4ac34cbbdb63ac80914ca842ed8e42938c40a53567806df3/websockets-16.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:6456ff333092d509127d75a638cb411afae8ff17f092635015d1902efec8a293", size = 177320, upload-time = "2026-07-17T22:50:06.427Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0f/45/ebec83e6269536aa5932533c67b0af5c781f3e73fdbcd68672dcf43f4f44/websockets-16.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:fce6c48559c86d1ac3632ccb1bebc7d5442fbe79bd9bb0e40379ee54be2a4051", size = 177544, upload-time = "2026-07-17T22:50:07.834Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/c9/d5/abc614d2297f6c1c3e01e61260364457a47c25cc1cf6a879038902bc6aa8/websockets-16.1.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:92b820d345f7a3fc7b8163949ee92df910f290c3fc517b3d5301c78065adafe1", size = 187270, upload-time = "2026-07-17T22:50:09.275Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/52/71/4c99af3b87dff1b2927981f6876607d4acb45338c665242168d3982f7758/websockets-16.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2a606d9c24035242a3e256e9d5b77ed9cd6bccfcb7cf993e5ca3c0f6f68fb6a7", size = 188509, upload-time = "2026-07-17T22:50:10.722Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/b4/5c8ca14b0df7eb84ed0524165c5359150210140817a3312aee57bf62a1cf/websockets-16.1.1-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:414e596c75f74e0994084694189d7dc9229fb278e33064d6784b73ffbba3ca31", size = 189882, upload-time = "2026-07-17T22:50:12.293Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/25/c1/bedfba9e70557129cb8083748d167bdcc01483dedf0f0df143676df05cbe/websockets-16.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:536676848fc5961aca9d20389951f59169508f765637a172403dc5434d722fa0", size = 189114, upload-time = "2026-07-17T22:50:13.789Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/df/09/aa835b2787835aebd839114be5de51b797cb480b63ba42b26d34dfe147cb/websockets-16.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:97fd3a0e8b53efa41970ac1dff3d8cf0d2884cadeb4caaf95db7ad1526926ee3", size = 187861, upload-time = "2026-07-17T22:50:15.179Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/20/26/f6408330694dbc9830857d9d23bc14ac4f6875127a480cfdda8d5ca21198/websockets-16.1.1-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7b1b19636af86a3c7995d4d028dbe376f39b4bf31541146f9c123582a6c94562", size = 185286, upload-time = "2026-07-17T22:50:16.741Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/9a/e0675e70dd8a80762cf35bb18799d3f290a4890ffe6439bc51d222796083/websockets-16.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:41c8e77f17294c0ac18008a7309b99b34ee72247ef10b6dff4c3f8b5ac29896b", size = 187935, upload-time = "2026-07-17T22:50:18.213Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/33/c1/3234cfb86afde01b81e9bddcc6e534c440975d60a13991259e833069ab3e/websockets-16.1.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:9f63bcef7f4b02b06b35fc01c93b96c43b5e88e1e8868676caacf493d5a31f3a", size = 186444, upload-time = "2026-07-17T22:50:19.67Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/89/87/9c15206e1d778923d8daa9657de07aa62ea815e13448319c98458c37b281/websockets-16.1.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:dab9eb87869da2d6ed3af3f3adf28414baae6ec9d4df355ffc18889132f3436c", size = 188409, upload-time = "2026-07-17T22:50:21.28Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/f2/00/cf5de5c67676de2d3eef8b2a518f168f6796595447a5b7161ba0d012915c/websockets-16.1.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:43e3a9fdd7cbf7ba6040c31fae0faf84ca1474fef777c4e37912f1540f854499", size = 185958, upload-time = "2026-07-17T22:50:22.719Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/62/c0/731b6ddede2e4136912ec4cff2cffbda35af73546be4762c3d7bd3bd79af/websockets-16.1.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:056ae37939ed7e9974f364f5864e76e49182622d8f9751ac1903c0d09b013985", size = 186911, upload-time = "2026-07-17T22:50:24.108Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/8c/7f/39c634472c4469a24a7c09cecddffb08fac6d0e74f73881a94ee8a40a196/websockets-16.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a0eadbbf2c30f01efa58e1f110eb6fa293261f6b0b1aa38f7f48707107690af9", size = 187204, upload-time = "2026-07-17T22:50:25.548Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/26/89/9667c256c256dafcc62d21328ce7a40067da857969b68ee9af375b0aaf72/websockets-16.1.1-cp314-cp314-win32.whl", hash = "sha256:195c978b065fa40910582464f99d6b15c8b314c68e0546549a55ed83f4735328", size = 179603, upload-time = "2026-07-17T22:50:27.086Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/bd/dd/1c099d6c0fc5deb6b46ccdbb6981fdb4b12c917869cb3952408409dc18db/websockets-16.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:4e8d01cc3bcae7bbf8167f944aeafefed590fae5693552bba9794a9df68371cc", size = 179948, upload-time = "2026-07-17T22:50:28.521Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/25/9956b2d5e0529d5d23924f21bba1440d4c5c88a562e4f08550871ffa97a7/websockets-16.1.1-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:0ffd3031ea8bda8d61762e84220186105ba3b748b3c8da2ae4f7816fac03e573", size = 179963, upload-time = "2026-07-17T22:50:29.982Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/17/06/55ffc976c488b6aee9ea05761ff7c4e88e7c1fd82818c8ca7b556ad2f90c/websockets-16.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:84a2cef8deffbd9ab8ee0ea546a2a6a7030c28f44e6cdd4547dbfeb489eb8999", size = 177497, upload-time = "2026-07-17T22:50:31.396Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/0c/e8/f7dac2e980bacc92bdc26cebae4ae4d50cae5380732c50980598fc0bbae4/websockets-16.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:3df13f73af9b3b38ab1195eb299ecb67a4330c911c97ae04043ff74085728abe", size = 177698, upload-time = "2026-07-17T22:50:32.829Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b2/39/26762f734113e22da2b942c3aca85798e0c0405d64c256549540ff31e5a1/websockets-16.1.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:23253dd5bcae3f9aaee0a1d30967a8dbd52e5d3cff93a2e5b84df57b77d4750d", size = 187561, upload-time = "2026-07-17T22:50:34.24Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/11/94/c3f330851806b9b02138b774d593478323e73c99238681b4b93efe64e02d/websockets-16.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c1c5705e314449e3308872fe084b8571ce078ee4fc55a98a769bdefe5917392", size = 188732, upload-time = "2026-07-17T22:50:36.088Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/d1/f2/eb2c450f052de334ae33cf200ece6e87b0e14d186807074e4eb1cd2cdea2/websockets-16.1.1-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:69e52d175a0a7d1e13b4b67ad41c560b7d98e8c6f6126eb0bda496c784faf8c7", size = 190872, upload-time = "2026-07-17T22:50:38.008Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/70/31/2ac8cecf3a74f7fed9132129fc3d90b3998a1554570c11a69b2a8c20332d/websockets-16.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1f79c89b5eb034d1722938a891916582f8f7f503f58ca22518a63c3f2cd18499", size = 189305, upload-time = "2026-07-17T22:50:39.53Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/6a/cf/8ab19650d3c0d4562c92e70ab47c257c4aa5c6a713ed87fe63766b31fefc/websockets-16.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:39f2a024af5c345ffe8fcf1ee18c049c024c94df393bb09b044a6917c77bde43", size = 188033, upload-time = "2026-07-17T22:50:40.912Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/66/d7/a49a38a6127a4acb134fb1912b215d900cc657605cff32445bf519f3acc4/websockets-16.1.1-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:952303a7318d4cbe1011400839bb2051c9f84fa0a35923267f5daba34b15d458", size = 185748, upload-time = "2026-07-17T22:50:42.559Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/95/3e/ad1fa40388c7f2e0bb2c7930d0090b6c5498594bd1cdaec18864df3d9e97/websockets-16.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:249116b4a76063d930a46391ad56e135c286e4562a18309029fc2c73f4ed4c62", size = 188285, upload-time = "2026-07-17T22:50:43.974Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/35/b8/d5db28ca264b9104f82196f92dc8843e35fd391f763d42e4ad358f5bc97e/websockets-16.1.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:61922544a0587a13fd3f53e4c0e5e606510c7b0d9d22c8444e5fae22a06b38cb", size = 186777, upload-time = "2026-07-17T22:50:45.474Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/42/9c/726cb39d0cc43ae848dce4aa2acb04eecc6738b1264ec6d700bf6bcfb9f8/websockets-16.1.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:46dcaa042cd1de6c59e7d9269fa63ff7572b6df40510600b678f0826b3c7af51", size = 188682, upload-time = "2026-07-17T22:50:46.973Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/c7/1168704de8c2dd483edabe4a22cbe4465dd8be8dd95561d214f9fe092871/websockets-16.1.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:38565aca3e01ea8734e578fb2118dade0ecb0250533f29e22b8d1a7a196cf4d0", size = 186377, upload-time = "2026-07-17T22:50:48.413Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/ca/40/f9ff2d630ffce4e7dfea0b2288e1caf9ebbf9ff8a9ec9396136ce8b94935/websockets-16.1.1-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:42f599f4d48c7e1a3338fdaac3acd075be3b3cf02d4b274f3bf2767aedd3d217", size = 187148, upload-time = "2026-07-17T22:50:49.845Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/b5/71/e177c8299f78d7cbe2d14df228643c10c70c0e86e108e092056bbcc16e46/websockets-16.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcc04fedf83effaeb9cce98abc9469bb1b42ef85f03e01c8c1f4438ef7555737", size = 187578, upload-time = "2026-07-17T22:50:51.619Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/49/b2/b6987faf330f5af5c787a2610124c2e8403d51724f9001ec4fff6311fe7a/websockets-16.1.1-cp314-cp314t-win32.whl", hash = "sha256:8483c2096363120eea8b07c06ae7304d520f686665fffd4811fad423930a65d7", size = 179729, upload-time = "2026-07-17T22:50:53.269Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/a2/6e/fbac6ed878dd362fbad7d415fa4f84d38e3e33fed8cde45c64e783acf826/websockets-16.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:bcce07e23e5769375158f5efdcdafa8d5cd014b93c6683865b840ed65b96f231", size = 180072, upload-time = "2026-07-17T22:50:54.969Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/e1/ed/71fea6e141590cafc40b14dc5943b0845606bee87bdb52a21b6a73eb4311/websockets-16.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:820fb8450edddae3812fd58cbc08e2bf22812cb248ecb5f06dbb82119a56e869", size = 177185, upload-time = "2026-07-17T22:50:56.665Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/01/ec/00e7eeca200facf9266a83e4cbbf1bed0e67fba1d4d45031d3e5b3d81b5c/websockets-16.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:125f22dbefaf1554fea66fc83851490edb284ce4f501d37ffed2752f418332d9", size = 177459, upload-time = "2026-07-17T22:50:58.197Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/75/fd/5774c4b33f7c0d8f0c51809c8b3a93456c48e3543579262cfa64eb5f522e/websockets-16.1.1-pp311-pypy311_pp73-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:30bbe120437b5648a77d3519b7024ea09530e0b5b18d3698c5a0ae536fe0cc2e", size = 178294, upload-time = "2026-07-17T22:50:59.641Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/37/c3/48e2c03d2bd79bb45948841c592d24156312dd5f58cdf8f549febe652fb6/websockets-16.1.1-pp311-pypy311_pp73-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b6b9dadbef0cccd9f4c4ee96b08898afa73e26803bbe0f6aeb5bb12b0074206d", size = 179190, upload-time = "2026-07-17T22:51:01.129Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/2d/3f/73e511ecf2496ceac57dd4ed8388efe2bcf0769338a2dbf242c8366ae87e/websockets-16.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56cd5fc4f10a9ea8aa0804bddb7b42506cf9e136046f3b4c27de8fec9e2ecba5", size = 180330, upload-time = "2026-07-17T22:51:02.603Z" },
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/be/4d/2d0d67834092e354d2b0498f014a41249a89556bc406cf86f3e1557bb463/websockets-16.1.1-py3-none-any.whl", hash = "sha256:6abbd3e82c731c8e531714466acd5d87b5e88ac3243465337ba71d68e23ae7e3", size = 173814, upload-time = "2026-07-17T22:51:04.184Z" },
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "xxhash"
|
name = "xxhash"
|
||||||
version = "3.7.0"
|
version = "3.7.0"
|
||||||
|
|||||||
Generated
+247
-242
@@ -3,7 +3,8 @@ revision = 3
|
|||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
resolution-markers = [
|
resolution-markers = [
|
||||||
"python_full_version >= '3.15'",
|
"python_full_version >= '3.15'",
|
||||||
"python_full_version >= '3.11' and python_full_version < '3.15'",
|
"python_full_version >= '3.12' and python_full_version < '3.15' and sys_platform == 'emscripten'",
|
||||||
|
"(python_full_version >= '3.11' and python_full_version < '3.15' and sys_platform != 'emscripten') or (python_full_version == '3.11.*' and sys_platform == 'emscripten')",
|
||||||
"python_full_version < '3.11'",
|
"python_full_version < '3.11'",
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -18,16 +19,16 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anyio"
|
name = "anyio"
|
||||||
version = "4.13.0"
|
version = "4.14.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
{ name = "exceptiongroup", marker = "python_full_version < '3.11'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/19/14/2c5dd9f512b66549ae92767a9c7b330ae88e1932ca57876909410251fe13/anyio-4.13.0.tar.gz", hash = "sha256:334b70e641fd2221c1505b3890c69882fe4a2df910cba14d97019b90b24439dc", size = 231622, upload-time = "2026-03-24T12:59:09.671Z" }
|
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 = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/da/42/e921fccf5015463e32a3cf6ee7f980a6ed0f395ceeaa45060b61d86486c2/anyio-4.13.0-py3-none-any.whl", hash = "sha256:08b310f9e24a9594186fd75b4f73f4a4152069e3853f1ed8bfbf58369f4ad708", size = 114353, upload-time = "2026-03-24T12:59:08.246Z" },
|
{ 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]]
|
[[package]]
|
||||||
@@ -158,7 +159,7 @@ name = "blockbuster"
|
|||||||
version = "1.5.26"
|
version = "1.5.26"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "forbiddenfruit", marker = "python_full_version >= '3.11' and implementation_name == 'cpython'" },
|
{ name = "forbiddenfruit", marker = "implementation_name == 'cpython'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/55/e0/dcbab602790a576b0b94108c07e2c048e5897df7cc83722a89582d733987/blockbuster-1.5.26.tar.gz", hash = "sha256:cc3ce8c70fa852a97ee3411155f31e4ad2665cd1c6c7d2f8bb1851dab61dc629", size = 36085, upload-time = "2025-12-05T10:43:47.735Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/55/e0/dcbab602790a576b0b94108c07e2c048e5897df7cc83722a89582d733987/blockbuster-1.5.26.tar.gz", hash = "sha256:cc3ce8c70fa852a97ee3411155f31e4ad2665cd1c6c7d2f8bb1851dab61dc629", size = 36085, upload-time = "2025-12-05T10:43:47.735Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -363,14 +364,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "click"
|
name = "click"
|
||||||
version = "8.4.2"
|
version = "8.5.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
sdist = { url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz", hash = "sha256:ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34", size = 382235, upload-time = "2026-08-26T13:33:14.56Z" }
|
||||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
|
||||||
]
|
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" }
|
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/fb/e2/79c688af8b210d232694e31e59da9f6ec747bae31c3f5946e4e9b98860d5/click-8.4.2-py3-none-any.whl", hash = "sha256:e6f9f66136c816745b9d65817da91d61d957fb16e02e4dcd0552553c5a197b76", size = 119243, upload-time = "2026-06-24T17:45:13.73Z" },
|
{ url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl", hash = "sha256:255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360", size = 125251, upload-time = "2026-08-26T13:33:12.928Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -384,11 +382,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "codespell"
|
name = "codespell"
|
||||||
version = "2.4.2"
|
version = "2.4.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/2d/9d/1d0903dff693160f893ca6abcabad545088e7a2ee0a6deae7c24e958be69/codespell-2.4.2.tar.gz", hash = "sha256:3c33be9ae34543807f088aeb4832dfad8cb2dae38da61cac0a7045dd376cfdf3", size = 352058, upload-time = "2026-03-05T18:10:42.936Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/80/19/45e941380f69c042b43423513d201e6592346f992394347f5e7174c31407/codespell-2.4.3.tar.gz", hash = "sha256:cbe085e331227b37bb86ef8bddd08dc768c704ee9a07ca869852c093fa2793e2", size = 352773, upload-time = "2026-07-15T11:51:54.159Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/a1/52fa05533e95fe45bcc09bcf8a503874b1c08f221a4e35608017e0938f55/codespell-2.4.2-py3-none-any.whl", hash = "sha256:97e0c1060cf46bd1d5db89a936c98db8c2b804e1fdd4b5c645e82a1ec6b1f886", size = 353715, upload-time = "2026-03-05T18:10:41.398Z" },
|
{ url = "https://files.pythonhosted.org/packages/8b/bf/bdb951d34eb169140b546f44be9ec4525d1acefb9eb5572071f5492b19fc/codespell-2.4.3-py3-none-any.whl", hash = "sha256:af2505b335e8573dbd2d384d1c4ef498f4006f4ba2d6fceca01e55b91f52628a", size = 340736, upload-time = "2026-07-15T11:51:52.925Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -405,7 +403,7 @@ name = "croniter"
|
|||||||
version = "6.2.2"
|
version = "6.2.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "python-dateutil", marker = "python_full_version >= '3.11'" },
|
{ name = "python-dateutil" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/df/de/5832661ed55107b8a09af3f0a2e71e0957226a59eb1dcf0a445cce6daf20/croniter-6.2.2.tar.gz", hash = "sha256:ba60832a5ec8e12e51b8691c3309a113d1cf6526bdf1a48150ce8ec7a532d0ab", size = 113762, upload-time = "2026-03-15T08:43:48.112Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/df/de/5832661ed55107b8a09af3f0a2e71e0957226a59eb1dcf0a445cce6daf20/croniter-6.2.2.tar.gz", hash = "sha256:ba60832a5ec8e12e51b8691c3309a113d1cf6526bdf1a48150ce8ec7a532d0ab", size = 113762, upload-time = "2026-03-15T08:43:48.112Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -414,62 +412,59 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cryptography"
|
name = "cryptography"
|
||||||
version = "48.0.1"
|
version = "50.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
{ name = "cffi", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/12/45/870e7f4bef50e5f53b9f51d4428aee5290eedf58ba443f16b1ebb7ab8e66/cryptography-48.0.1.tar.gz", hash = "sha256:266f4ee051abb2f725b74ef8072b521ce1feacf685a3364fa6a6b45548db791a", size = 832989, upload-time = "2026-06-09T22:32:31.8Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/de/41/6cbdcf9142d00fe82836fbb51e503e58088575cf7a0fe1dbff6695bf0840/cryptography-50.0.0.tar.gz", hash = "sha256:eeac2acb5a20ed25e0ad6d1df9891a520b78b404266b6d11778f25d5d691a6c9", size = 880201, upload-time = "2026-07-31T14:25:10.11Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/1b/bc/ee4137cbbe105652c0ee4252792b78fc8e7afa4b8e61d9d5dc05a7f45731/cryptography-48.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:3e4a1a3232eef2e6c732827d5722db29a0cc8b27af2a4d865b094cf954be9ca1", size = 8008324, upload-time = "2026-06-09T22:31:00.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c5/5c/59086b4aac5e879d38ddbcf74e4be7ade89cebc3eb199a55da998c3bb46a/cryptography-50.0.0-cp311-abi3-macosx_11_0_arm64.whl", hash = "sha256:031e2d5dd4bb9caa3ca9c82e5a197fd8ae680232cee62603d1a813f3f07e3d03", size = 4001252, upload-time = "2026-07-31T14:23:33.331Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d5/85/6379d42181bfc713094f081360fc5784d6c816b599d45e7f082502d173ce/cryptography-48.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:32143b24adb918f078134e1e230f1eb8cc04886b92c28b5f0041aaf3e5699225", size = 4696243, upload-time = "2026-06-09T22:32:33.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/57/ef/8f2df13c7216bcad3e1c74e07f6e193d93e998e114f524a53877c9af27ad/cryptography-50.0.0-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:fd9192b7b70c573d7f214eb1ae35e00d359f6f5e4b27c7e21e30de1fc6204645", size = 4719554, upload-time = "2026-07-31T14:23:35.611Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9c/87/c85d147b53323c7eb4d850920c8901377323c2a0ff8d79c262d4fee89aa2/cryptography-48.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f0d27a5696721ef7a672b8c810f6aded391058e0b9486e63e6d93baf765da691", size = 4713235, upload-time = "2026-06-09T22:31:40.141Z" },
|
{ url = "https://files.pythonhosted.org/packages/d9/41/029086c34d91052fc3b88bcc8056f709a7c915c7a23b235a54eb800b1c97/cryptography-50.0.0-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:06a32a980526a6ab9a4b9bf8f7385800791e2bb960903cb6b530e4817509a3b7", size = 4702130, upload-time = "2026-07-31T14:23:37.635Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/58/67cbf8cf1ee7c54b439ca07bbecf8362c07afc11a3724fea70f745784add/cryptography-48.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:eb86ce1af36fe65041b6db9a8bb064ee621a7e5fded0f80d475ec243477cd242", size = 4702323, upload-time = "2026-06-09T22:31:42.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/7d/ff/b6ce0954962e7f7b969f850a883744197bb3910bdfd7b6da162eab7d9f68/cryptography-50.0.0-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:a1b30560f2acc95aa8b2e06e716a13dbfc97314747b80d9707e307f77b40d6b3", size = 4725244, upload-time = "2026-07-31T14:23:39.471Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/89/c6/24266ac10c47f6cd2a865f4446062b466da1d1f10b27189eac00e61bf0c9/cryptography-48.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:b024e784ad6c077ee0147b35ea9cbfc1e34e1fd4c1dcca214c2794d73a12df08", size = 5300085, upload-time = "2026-06-09T22:31:58.703Z" },
|
{ url = "https://files.pythonhosted.org/packages/06/1e/63a1027cb7fec360a182208e1b7767d5aa1fe57be3d6aa856e69a321edc0/cryptography-50.0.0-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:8d89f3976b10b4ce31118de72329025f70d2c6ead14a8217c5514dd2c6d5a78f", size = 5342265, upload-time = "2026-07-31T14:23:41.286Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d2/bb/cc4b78784f97efc8c5874c2a9743708d172be6663024b34a0467885ae0c8/cryptography-48.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3752f2dbc8f07a30aad2932c986cea495b03bb554887828225da104f732852b6", size = 4746137, upload-time = "2026-06-09T22:31:31.01Z" },
|
{ url = "https://files.pythonhosted.org/packages/6b/72/a1116d683a6d7ece94590013882515de087edf9ef0e6292aae615a44df73/cryptography-50.0.0-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:b42a28c1844fd9de8f3f7d540e36b66f3a9c83fceac7170ebc7a6a19edd9dcae", size = 4734609, upload-time = "2026-07-31T14:23:43.139Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1f/52/0c44de3f5267f8fbe8e835138017522a333436166e406f0db9b9e6e3033f/cryptography-48.0.1-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:bd81490cd5801d755cf97bb68ac191f14b708470b1c7cf4580f669b9c9264cd8", size = 4333867, upload-time = "2026-06-09T22:32:28.096Z" },
|
{ url = "https://files.pythonhosted.org/packages/15/37/36a9c479bbe49acea2636c7fd3360d20f7b7e079c300352011c44850b181/cryptography-50.0.0-cp311-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:900131fafd8aead39ac7dd3a7e833be754c17a95cfd91221636949fe4eb0aa8a", size = 4356517, upload-time = "2026-07-31T14:23:44.939Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9a/2e/772d7adbfa931537bc401640b7cac9976bff689bda187833e5d63b428e49/cryptography-48.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:66fd0771e7b9c6dcd44cf1120690d2338d16d72795cf40cae2786a39eba65429", size = 4701805, upload-time = "2026-06-09T22:31:38.284Z" },
|
{ url = "https://files.pythonhosted.org/packages/32/98/8a151d64367204cbc63ec65d37502f1d9c53cf4bfc6ec3c532614dbec60d/cryptography-50.0.0-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:07949c449a1abcf60d1ee6e88956d89404c7df3c8258f46589e912988e551987", size = 4724529, upload-time = "2026-07-31T14:23:46.93Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f8/a3/b06844f303873493c963caf581c04df31c7035e0c1b0f02c4814d319ec80/cryptography-48.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:3fd2ca57062b241c856670b073487d2e86c4637937ca5601e48f97bf8e11fc8f", size = 5258461, upload-time = "2026-06-09T22:31:04.187Z" },
|
{ url = "https://files.pythonhosted.org/packages/22/f6/ec13b470172126464a86bf54d2294a46d29837fc51ba3e45d4047946fb5e/cryptography-50.0.0-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:f89831ef99dd7dd169ab06d63a831adb9e20a87aac6d380266bbda5823349169", size = 5299852, upload-time = "2026-07-31T14:23:48.851Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/13/8b765e2e12b07c74941caadb9d1c8fdc006c4dfbf2b8f2d610519758954d/cryptography-48.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:0ee6ea481db1ab889cba043ec1eda17bb9c1ea79db6722f779c3667f9f70322f", size = 4745488, upload-time = "2026-06-09T22:32:30.07Z" },
|
{ url = "https://files.pythonhosted.org/packages/da/3a/f05e32c99d440c9bb891ea0e36c9091891e36be5a9a87ab2ee6ea20729f6/cryptography-50.0.0-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:82148ec5bddac30b51a5b3c1945075f896fa022cb93f8e4a01e9f6ee95292c5f", size = 4734462, upload-time = "2026-07-31T14:23:50.861Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/2e/aa/48972bce55049b32a94f4907eda4d75fa385aad8a39506cc2fc72196ecf0/cryptography-48.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f2ceef93cb096aa3c4cc4b5c94ca6131f9196d28c64d6111533402a9b2054d41", size = 4830256, upload-time = "2026-06-09T22:31:43.868Z" },
|
{ url = "https://files.pythonhosted.org/packages/ca/dc/bd72b26be8953f80625f63151efd38eee71c76ca6cf591c08ff34615a79e/cryptography-50.0.0-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1489e263a8048bb8b6a8bac662eb2d402ea5d2b7b4699b72f385f1e2772db105", size = 4852708, upload-time = "2026-07-31T14:23:52.715Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/a2/e5079a032fb85cf6005046ca92bbd78b0c82dad2b5751ab8c311659da06f/cryptography-48.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9bd3f92d76217892b15df84ca256c2c113d386fdda7a7d8691aeeced976507c6", size = 4979117, upload-time = "2026-06-09T22:31:05.845Z" },
|
{ url = "https://files.pythonhosted.org/packages/27/20/c930314a2ab476d15dec966ec87e2e9637bb02b06106b12c0396c57bb603/cryptography-50.0.0-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7cec5b856506da6defb290f30c9ee687d5f5e8cb0bd3f6459dde43b0b4fa40ef", size = 5004179, upload-time = "2026-07-31T14:23:54.887Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b7/a0/8f50cae9c74e718ed769d63ed5c74bd0ea830c9550a74629cebd1b9c7bc7/cryptography-48.0.1-cp311-abi3-win32.whl", hash = "sha256:b9a32b876490d66c8bcc9963ef220199569748434ab01a9d6aaeabf88e7f5158", size = 3304154, upload-time = "2026-06-09T22:32:16.845Z" },
|
{ url = "https://files.pythonhosted.org/packages/32/2e/c9db68a0c4bfa28e310707527c0ee3a2bd254104d2e02e68f368e197aa4c/cryptography-50.0.0-cp311-abi3-win_amd64.whl", hash = "sha256:bd1c592e4d5974f0d08d4888e432157adba757c66da0246918e43677fafa2d30", size = 3840395, upload-time = "2026-07-31T14:23:56.677Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c5/69/0572c77dbace6fef72f33755bd52ea399c71367250d366237f8691826b9e/cryptography-48.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:39489bfca54c7a1f6b297efcd8bc608ab92d16c4ca631b0cad4da46724588b24", size = 3817138, upload-time = "2026-06-09T22:32:00.388Z" },
|
{ url = "https://files.pythonhosted.org/packages/c3/fb/951032a3bf22a5697c83183fb6294a4843772947a70e616c57b3ff5f522e/cryptography-50.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:49e7d93abdbd2990caced757e5fade25302f719c3c8fb6e6fff2dde98999fc41", size = 3989258, upload-time = "2026-07-31T14:23:58.881Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/06/3e768b4c3bc78201583fa35a0e18f640dd782ff41afba88f8545481a8874/cryptography-48.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:f817adc181390bd54f2f700107a7419040fb7c1bdf2fc26f36551a06a68c3345", size = 7989830, upload-time = "2026-06-09T22:31:07.8Z" },
|
{ url = "https://files.pythonhosted.org/packages/d4/67/91eb047e69c5e845f2f14b8a2e4a1aab0f283cb885531e9e22c8adb176bc/cryptography-50.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:19736989797678c6af1e55cd49055cdbcb55d8f6b5583ac5335f933aba9101dc", size = 4700648, upload-time = "2026-07-31T14:24:00.702Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/8a/13/6476736484b94041110c8340a3eb63962fea4975baea8cb4a512adb44d4d/cryptography-48.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d5d30989c6917b478b5817902e85fddaea2261efa8648383d965381ccb9e1ac4", size = 4689201, upload-time = "2026-06-09T22:31:09.745Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/82/85f0f7425c856b9f96459411eb12e74ef72df9caf6f8f15bf23a33ff131f/cryptography-50.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:80b63928fa35083b33966ce1efb70e5b9607181e49dcd1c22c8c005e319f667f", size = 4682442, upload-time = "2026-07-31T14:24:02.538Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/79/62/65a87f34d2a431546e2509b85d55e8c90df86d668f6731da64d538512ac2/cryptography-48.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:df637c05205ea7c1d7fbcbe54bbfea648a52951155f997af13d895d0ecc96991", size = 4702822, upload-time = "2026-06-09T22:32:24.409Z" },
|
{ url = "https://files.pythonhosted.org/packages/1a/28/b555a365adff1cca2fbe7b9e487d68a40de6bc67ff2cb587473eb43de0e7/cryptography-50.0.0-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:d58c3db7cd6eed54e6c06744db55456b65ebd7492ddeae9c1e93cfca7aa857d3", size = 4707596, upload-time = "2026-07-31T14:24:04.394Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7f/59/810b5204b0a9b10f4b6bc06bd551a8b609803cd931806bc3b71884b225e5/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:869c3b8a53bfe27147832df48b32adadf558249d50e76cb3769d40e986b13265", size = 4694875, upload-time = "2026-06-09T22:32:08.737Z" },
|
{ url = "https://files.pythonhosted.org/packages/72/d8/f52538140cc719df62a01cf87d1c7142318d235817109d6f4054d7c352d6/cryptography-50.0.0-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:df2a58a472f332225671c35b0a830208b86d004f82baa8530fa3782c85646533", size = 5314552, upload-time = "2026-07-31T14:24:06.31Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/dc/d8ca05ffea724eec6d232ea6f18e74c269eb6bdfdcc9bfba689790d1325f/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:e361afba8918070d376df76f408a4f67fec0ee9cff81a99e48fe9a233ef59e17", size = 5290385, upload-time = "2026-06-09T22:31:15.212Z" },
|
{ url = "https://files.pythonhosted.org/packages/38/14/6120e5bd7c5aa022ad15424ba4d5c5269d0d9448ed4d55e492ea91e3c1c4/cryptography-50.0.0-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:11b74db56cdbe3cdee6e3f6982ecb70334fa10dce99ed58bf7894aaaa3b2a037", size = 4717113, upload-time = "2026-07-31T14:24:08.349Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/03/8c/3be6cb4da181f5bb6c19cf560c2359d60644a6b5fc5b57854e528f47b296/cryptography-48.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:d069066deead00ac7f090be101be875a06855908f7ec004c27b8fefb4acfb411", size = 4737082, upload-time = "2026-06-09T22:32:22.66Z" },
|
{ url = "https://files.pythonhosted.org/packages/fa/71/190bf38c3ee2e0f8efc9860ae100c9df4169742eef274b91e7aa1cb133b9/cryptography-50.0.0-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:f59e38625469987d7ef6d495323c55e7db6c212eaf6112267e0d3b565a2e9c9f", size = 4338580, upload-time = "2026-07-31T14:24:10.227Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/f6/d5f60a5a1434dbfd949e227fd0065d194c7e6b6ac526b17f5c06152b8231/cryptography-48.0.1-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:09f73a725d582cef64b91281a322cd798d14a33b2b6f2b7ad9531dc336d84c02", size = 4325328, upload-time = "2026-06-09T22:32:10.777Z" },
|
{ url = "https://files.pythonhosted.org/packages/3a/63/504ccfbbe61fd8aa983f7f146399cdf034c72c2fc55f5b2dfdcdcdb20c99/cryptography-50.0.0-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ecfed7367f965a0328cfbdd70da860f15441f002f613185668c6e6ebf5a0ac11", size = 4707038, upload-time = "2026-07-31T14:24:12.169Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/17/b7/ba75dd947a14b6ad907b01ae8f6b5b348cdd1b48142f0063dee9e20c1d9d/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:15254441469dd6bf027039453288e2072124f8b6603563f5d759e1c9b69273fa", size = 4694530, upload-time = "2026-06-09T22:31:53.105Z" },
|
{ url = "https://files.pythonhosted.org/packages/01/77/2cf79bbfc4d12ca106437a6e170d6aaa01a373e93093118aaaef0e801bd4/cryptography-50.0.0-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:9aa87839c383bdbab6ef865787a1fb877af8dd03464c4400322726feaaadfc6d", size = 5273110, upload-time = "2026-07-31T14:24:14.38Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/62/29/50d6b9e8aff12d8b67afaeb3569335e32dc83a5723e3bbded24fdac9f809/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:8ace4507d1e6533c125f4fac754f8bb8b6a74c08e92179dabd7e16571a3efbf3", size = 5245046, upload-time = "2026-06-09T22:31:25.774Z" },
|
{ url = "https://files.pythonhosted.org/packages/e5/45/8aae2972c520145377ea3559a605a899bebe227bf070b33cdb445929a9b9/cryptography-50.0.0-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:6ba6a53445bd3cfa809ef3ef5f1589aa6ba08784a1d962bf47d0940e871dab1c", size = 4716439, upload-time = "2026-07-31T14:24:16.415Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/9f/04/618f4115cfc0add0838c82507aa18a346089428da8653ad38b3ff36f5cb3/cryptography-48.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:b4e391975f038e66432328639620a4aff2d307513b004f1ca06d6225bced815c", size = 4736660, upload-time = "2026-06-09T22:32:12.676Z" },
|
{ url = "https://files.pythonhosted.org/packages/7b/20/4fe50b619a48c2525cc46e2dbc1ac490708d704be5d467bdaac6dc955682/cryptography-50.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3f5735ffe4996d28b809371756219f5354864902a3b9e7c0b9ee87041209fc9c", size = 4837383, upload-time = "2026-07-31T14:24:18.553Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/24/9c/06e062462a0de28a3b3911322eded4c16deb9f441b1b7575d3dc59488ab5/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:42fcd8e26fe555d9b3577a135f5091fefa0aa4e99129c23fb56787a1bd4ada72", size = 4822229, upload-time = "2026-06-09T22:31:17.062Z" },
|
{ url = "https://files.pythonhosted.org/packages/92/91/3a31366e183343d3703f8995c095f5734676bd6938118047e50fcf279eb4/cryptography-50.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1b4a266766514614f8aa60416e71f2fc6e575d36e7bdc90f644fadb2f4b75b95", size = 4985772, upload-time = "2026-07-31T14:24:20.385Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f4/be/0561971eaaee4b8a0e7d5113c536921063ab91aaf23278ac374eaf881e11/cryptography-48.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:c1400da5e32a43253392277eac7490a60e497d810a63dd5608d71bbd7af507c9", size = 4966364, upload-time = "2026-06-09T22:31:32.842Z" },
|
{ url = "https://files.pythonhosted.org/packages/74/9a/02ffe35b2853d121689871eb5dce862092562b3a1ed5cc98f1aaed441506/cryptography-50.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:12b9c6996425c76ea6c457ace4f3073e715b8c545add07cd1a8f3a4f90691269", size = 3816291, upload-time = "2026-07-31T14:24:22.125Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a4/27/728c77876f12b000820b69ae490f3c4083775e79e07827e9e60be07ad209/cryptography-48.0.1-cp314-cp314t-win32.whl", hash = "sha256:0df56b056bc17c1b7d6821dfa65216e62bd232d8ab05eb3db44e71d235651471", size = 3278498, upload-time = "2026-06-09T22:31:29.154Z" },
|
{ url = "https://files.pythonhosted.org/packages/03/37/73d005be173aff344af30e9fd2a576575cb2391a7101d9cd3842e1fa8cce/cryptography-50.0.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:ccdc4a71a4dabae05de219404f9f4abc38e3b58422177ff93d0da05967dafa07", size = 4036009, upload-time = "2026-07-31T14:24:24.122Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/06/e3/79a612c6d7b1e6ee0edd43633d53035bec2cfb78c82b76f7864f39e36f34/cryptography-48.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:9de21387aa95e2a895823d0745b430bed4f33503ba9ab5e0b5311f33e37d66d2", size = 3798790, upload-time = "2026-06-09T22:31:56.697Z" },
|
{ url = "https://files.pythonhosted.org/packages/ff/c6/7a6202a534e32103a285b7834a120869557fe198d51d7cfe59754c8bda9c/cryptography-50.0.0-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:910e1d2668e7de9648f2bcee30e180db2a6b15c30f887d7c4c93ddf96e3992e3", size = 4745252, upload-time = "2026-07-31T14:24:26.118Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/6c/00fa2a95997164c8b2072ce327c23d4ab20809ccc323ea5fab91e53a4bba/cryptography-48.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:4fdc69f8e4316bcf0c8c8ec1f26f285d12e8142d88d96c876a59a03be3f6ae67", size = 7987408, upload-time = "2026-06-09T22:32:20.777Z" },
|
{ url = "https://files.pythonhosted.org/packages/85/4f/0fa8c2f4428198f15d9ff8d63400e27afbf94ce833f6108da1eb3753f945/cryptography-50.0.0-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a91296cb61e8df6f86d0c19cc4068228da256bf59bf86049fbd821084565327f", size = 4728939, upload-time = "2026-07-31T14:24:27.994Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/d9/45f309a7e4e5f3f8f121d6d3be9e94024a7726ec598d6e08ae04edb2f04d/cryptography-48.0.1-cp39-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:48fe40804d4caa2288f24e70ca8c64c42dd826da0ad7e4f1b41b2128d679e6c8", size = 4690196, upload-time = "2026-06-09T22:31:54.74Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/63/54dd723490ba2dc09b299682c10b38db38f159728bcaae8c591b8af2f22d/cryptography-50.0.0-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e722f16708d854fe924790e051061f6704a472c3bac347b6fd88033ea8dd0dc5", size = 4748483, upload-time = "2026-07-31T14:24:30.254Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5f/9f/a1bc8bcc798811b8527eb374bbccf30a3f3e806829d967118222bf1125eb/cryptography-48.0.1-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:86be3b1b0b6bf09482fb50a979c508d2950ed95f5621ec77f4e385962006b83a", size = 4696782, upload-time = "2026-06-09T22:31:45.615Z" },
|
{ url = "https://files.pythonhosted.org/packages/1d/dd/7c77d26285cc7f6991efce64a0f5b4f9383bfa5dd8c5033003eaf7db4cdb/cryptography-50.0.0-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:d764dcf130c428ef66786f866dd750f53182bc608813489915e9fc106bb0c82f", size = 5367599, upload-time = "2026-07-31T14:24:32.457Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/66/c2/81a4fb4e4373c500bb526bc337ac5719dd31dd15b970b84a238168c6aa08/cryptography-48.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:4ab0a343c807bbcd90c971cd1ecf072937cd01847a9e002bef88fb47ac6be577", size = 4696618, upload-time = "2026-06-09T22:31:11.564Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/c9/f60aed34c013f317f92817b6c171c2d22a78270fa41109bd4b08af26b194/cryptography-50.0.0-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:105110f43a471dbd0060b9c9516cb8a6a79233631a04cc2ba16f28323ac6e025", size = 4762647, upload-time = "2026-07-31T14:24:34.599Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e5/0b/aa68b221dde92d09cb29a024ede17550ee21e77a404e59fc093c82bb51e1/cryptography-48.0.1-cp39-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:9621de99d2da096006b629979efd8ae7eb2d8b822488d0c89ee4000c306c59b1", size = 5289970, upload-time = "2026-06-09T22:31:20.368Z" },
|
{ url = "https://files.pythonhosted.org/packages/be/f3/f9a0173b139372c3a48ed98154b45cc6b9de17c789d5ab552e621c293609/cryptography-50.0.0-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:828743d939e9629bc267b8e2d08d8bb67cd4319c771a33d4b18b22dd8fb7440a", size = 4385197, upload-time = "2026-07-31T14:24:36.647Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/78/13/fba657f958d2af66ea959a4ba01212632089249d34af1ae48054136344d7/cryptography-48.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:88c852a0ae366e262e5a1744b685e6a433dc8788dd2a277e418bf4904203609d", size = 4731873, upload-time = "2026-06-09T22:31:22.253Z" },
|
{ url = "https://files.pythonhosted.org/packages/d8/36/83bb81f6e569bc38e1e4a7bc80f29b46bb9601920bc455fc8e888f5d5742/cryptography-50.0.0-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:2a8183b489dc1f7f80f135780fadc1108f14b31b8a40411c7a5b17425f65f28b", size = 4748095, upload-time = "2026-07-31T14:24:39.493Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/4c/9a964756d24a26b3e34dfcb16f961b89838786e6700b635b0d1e3adff4b6/cryptography-48.0.1-cp39-abi3-manylinux_2_31_armv7l.whl", hash = "sha256:43c5835e2cb98c8733d86f57d6fc879b613f5c3478607281c3e36daffc6dd8a6", size = 4330804, upload-time = "2026-06-09T22:31:36.56Z" },
|
{ url = "https://files.pythonhosted.org/packages/6b/16/d3008eff98c764979865834c3d386d4fd041b5f52e7f34fc29ac1a5eb515/cryptography-50.0.0-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:6e7d61120573a7f2cd94cc095f9e81f6967c61ccdf194285aa143ecec8e0b708", size = 5325948, upload-time = "2026-07-31T14:24:41.556Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/0f/a10f3a6eb12950a10e3a874070283aa2dd5875b2bfd15fad8a3e17b3f13e/cryptography-48.0.1-cp39-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:fe0180af5bf9236518a087e35bf2d9a347d5f5f51e63c579d683ddff424e3d46", size = 4696217, upload-time = "2026-06-09T22:31:13.351Z" },
|
{ url = "https://files.pythonhosted.org/packages/9c/f8/d97f9603efda3888187bfdb893f26c41be4735c10631d05d284ee6b047c4/cryptography-50.0.0-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:37fdb0d0111f1e2ff07139dfb79f1b49531f8e213c46f1163dd7642979b58c47", size = 4762400, upload-time = "2026-07-31T14:24:43.636Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/f3/6f/5cd12f951165ea73ef85266775d97e4c763b2474ccfd816dd69d3a18d6f8/cryptography-48.0.1-cp39-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:b7a2d1a937a738a881737cec135a38bb61470589b17515b9f73f571d0ae10401", size = 5245252, upload-time = "2026-06-09T22:32:02.193Z" },
|
{ url = "https://files.pythonhosted.org/packages/64/a2/4615c8f7d81a00b1d6e6afe19f694e1543582349fb5f4076f6cb5dc36485/cryptography-50.0.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:c87f62a3d3b9888ed0fdde100ec06aa61ca9cd44bad9057d1dff9a516b5f5bb9", size = 4878208, upload-time = "2026-07-31T14:24:45.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/68/ab/8aaa12e4516ec4464033ab79b6f3b592bd5a92102467c4ace8a0d970203f/cryptography-48.0.1-cp39-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:b74ca3b8e5ecdd833bf6a002ca41b4793bb27fb8f1c06ffaf2643c9e9140e31b", size = 4731388, upload-time = "2026-06-09T22:32:04.019Z" },
|
{ url = "https://files.pythonhosted.org/packages/d2/1a/efcfb02f91407149a0dacffffab791f7e19bf6385f63b3666dc8b5e5c9c8/cryptography-50.0.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:65c2c3add92b45fd0709db8594536aea39c2a67af0e27ffcf049c498501140b7", size = 5037050, upload-time = "2026-07-31T14:24:47.697Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/1b/24/50027ea4dca85ec1f40688f3c24fb32ccacd520583c9592c3cc95628e6fb/cryptography-48.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2c37f2461406063b417837f5f3daab668652acd82423efcd7f0a9f04be972de1", size = 4824186, upload-time = "2026-06-09T22:32:18.707Z" },
|
{ url = "https://files.pythonhosted.org/packages/57/30/4a22984d4f1bdfb8c054f07a92bc176b97a3134cc1d6c4b3bffb1f3688b4/cryptography-50.0.0-cp39-abi3-win_amd64.whl", hash = "sha256:d24fead1d4d076e1bfb006dcec392074a3cd8d7b4fc8a595aa64073b2b7a96ba", size = 3874135, upload-time = "2026-07-31T14:24:50.085Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/52/41/04cb5eb17085ade6f50cc611fb657df6a0f5885350de8764ece89c050197/cryptography-48.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:86fe77abb1bd87afb251d4d02ada7ecf53a32cee9b67d976abb2e45a13297475", size = 4964539, upload-time = "2026-06-09T22:31:18.793Z" },
|
{ url = "https://files.pythonhosted.org/packages/9d/3e/e54cde8c01631a5a8226ccd617eab9e57fd5cfdad90f1a9e6bb570794631/cryptography-50.0.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:5e34edd123674534acd70147f0ca331eaa2c74e6325fb2028c886aa26ba0b68c", size = 3963170, upload-time = "2026-07-31T14:24:51.968Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/36/bf/ed70785c496e89d7e73b7cda2d21f2447fd6d4e821714b8d04ff217fed92/cryptography-48.0.1-cp39-abi3-win32.whl", hash = "sha256:6b2c0c3e6ccf3ade7750f836ef3ee36eea250cc467d45c256895573ac08cc6f1", size = 3282307, upload-time = "2026-06-09T22:30:53.162Z" },
|
{ url = "https://files.pythonhosted.org/packages/01/b6/0b9e125e90f3d2dcf599a218a899cda7326a3158cfa258723f0b398b08f6/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:8eb5e1172eb569ea8a872796576e6a67c276351728b6455d5beb01242b027c6a", size = 4692441, upload-time = "2026-07-31T14:24:53.743Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/ff/371ea7d252656ee1eb6d83eeeef3d1d0c6baf1d6497687d081ea03814670/cryptography-48.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:9a49ca6c81417f6a5edb50375a60cccdd70fa0a91a5211829dbea74eba94d2ac", size = 3793408, upload-time = "2026-06-09T22:32:15.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/c9/a5151588710785a96d7bc4de27d4cd62f263bbbcb203cfe29df537eb6505/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:910d11e1a385c654bf738bf3e6b8e6ed5de0f5610fcae2be9e5b398d8081d20e", size = 4699810, upload-time = "2026-07-31T14:24:55.746Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a9/d3/eb4e394e587341fdad09a09101fa76478ead3a78b0ad63e55c22f0d75c02/cryptography-48.0.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:08a597acce1ff37f347400087776599e2348a3a8bc53b44120e463cd274efe4a", size = 3951747, upload-time = "2026-06-09T22:31:23.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/c7/1a/15b92b25eb6ce3089cd49377ae990a0f3ad485a510f968aed1f19dbdcdf2/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:62598a8a57f815db4c6259a4e97d857dab56697e7de8e8ab02352ab74da1995d", size = 4691924, upload-time = "2026-07-31T14:24:58.082Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e0/4a/3f43451b4f858bfceaaaffc649e6e787e8d4fb332a1d443af39ab02cc8f1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:735824ec41b7f74a7c45fb1591349333e4c696cb6c044e5f46356e560143e4cd", size = 4641226, upload-time = "2026-06-09T22:31:02.532Z" },
|
{ url = "https://files.pythonhosted.org/packages/62/15/219075012ab13e8905f3cd572204f4acb4b111df787104346b9bc0cea789/cryptography-50.0.0-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:07479a1cb08219ab719147e742e76090c9c773321959bb94946fffdd397a6437", size = 4699593, upload-time = "2026-07-31T14:24:59.951Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/73/4e/855584c2c23b09e4ce2d3b9c30e983e679cd60b068c513c6bbdb91e11782/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:92a46e1d638daa264ba2971c0b0489c9409787943efae4d60ffda3d091ef832c", size = 4668958, upload-time = "2026-06-09T22:32:06.213Z" },
|
{ url = "https://files.pythonhosted.org/packages/8e/b5/c2c5fce26f0ee40d21bafe7f191d29a34b35a65ac4fe8a1191d1983612e9/cryptography-50.0.0-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:c99c003e088647b8a5b7c145d6f78c335f6348332b62e142d411c4b63d1460b9", size = 3813796, upload-time = "2026-07-31T14:25:02.298Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/42/3b/d35750e41d803d1e516fd6d6011f065424924da7af1748cef4cc9cb3ede1/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:7e234ac052af99f2700826a5c29ea99d9c1b1f80341cde62d11c8154dc8e0bd9", size = 4640793, upload-time = "2026-06-09T22:32:26.331Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/aa/cdb7181fe865285e87e96825aaab239400f1de0c3bfba9bd9769b79f1a92/cryptography-48.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:33842cf0888951cef5bc7ac724ab844a42044c1727b967b7f8997289a0464f92", size = 4668505, upload-time = "2026-06-09T22:31:27.534Z" },
|
|
||||||
{ url = "https://files.pythonhosted.org/packages/5d/8c/ce3823c06c2804f194f9e64f0d67fa3f4094a39f2bb1a990cd03603af8fc/cryptography-48.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6184ca7b174f28d7c703f1290d4b297217c45355f77a98f67e9b7f14549ac54a", size = 3742204, upload-time = "2026-06-09T22:31:34.773Z" },
|
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -501,7 +496,7 @@ name = "exceptiongroup"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
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" }
|
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 = [
|
wheels = [
|
||||||
@@ -528,7 +523,7 @@ name = "googleapis-common-protos"
|
|||||||
version = "1.74.0"
|
version = "1.74.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
|
{ name = "protobuf" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/20/18/a746c8344152d368a5aac738d4c857012f2c5d1fd2eac7e17b647a7861bd/googleapis_common_protos-1.74.0.tar.gz", hash = "sha256:57971e4eeeba6aad1163c1f0fc88543f965bb49129b8bb55b2b7b26ecab084f1", size = 151254, upload-time = "2026-04-02T21:23:26.679Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -540,7 +535,7 @@ name = "grpcio"
|
|||||||
version = "1.80.0"
|
version = "1.80.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/b7/48/af6173dbca4454f4637a4678b67f52ca7e0c1ed7d5894d89d434fecede05/grpcio-1.80.0.tar.gz", hash = "sha256:29aca15edd0688c22ba01d7cc01cb000d72b2033f4a3c72a81a19b56fd143257", size = 12978905, upload-time = "2026-03-30T08:49:10.502Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -601,8 +596,8 @@ name = "grpcio-health-checking"
|
|||||||
version = "1.80.0"
|
version = "1.80.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "grpcio", marker = "python_full_version >= '3.11'" },
|
{ name = "grpcio" },
|
||||||
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
|
{ name = "protobuf" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d1/a2/aa3cc47f19c03f8e5287b987317059753141a3af8f66b96d5a64b3be10b8/grpcio_health_checking-1.80.0.tar.gz", hash = "sha256:2cc5f08bc8b816b8655ab6f59c71450063ba20766d31e21a493e912e3560c8b1", size = 17117, upload-time = "2026-03-30T08:54:41.899Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/d1/a2/aa3cc47f19c03f8e5287b987317059753141a3af8f66b96d5a64b3be10b8/grpcio_health_checking-1.80.0.tar.gz", hash = "sha256:2cc5f08bc8b816b8655ab6f59c71450063ba20766d31e21a493e912e3560c8b1", size = 17117, upload-time = "2026-03-30T08:54:41.899Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -614,9 +609,9 @@ name = "grpcio-tools"
|
|||||||
version = "1.80.0"
|
version = "1.80.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "grpcio", marker = "python_full_version >= '3.11'" },
|
{ name = "grpcio" },
|
||||||
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
|
{ name = "protobuf" },
|
||||||
{ name = "setuptools", marker = "python_full_version >= '3.11'" },
|
{ name = "setuptools" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/94/c8/1223f29c84a143ae9a56c084fc96894de0ba84b6e8d60a26241abd81d278/grpcio_tools-1.80.0.tar.gz", hash = "sha256:26052b19c6ce0dcf52d1024496aea3e2bdfa864159f06dc7b97b22d041a94b26", size = 6133212, upload-time = "2026-03-30T08:52:39.077Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -683,7 +678,7 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "hatch"
|
name = "hatch"
|
||||||
version = "1.17.0"
|
version = "1.18.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "backports-zstd", marker = "python_full_version < '3.14'" },
|
{ name = "backports-zstd", marker = "python_full_version < '3.14'" },
|
||||||
@@ -706,9 +701,9 @@ dependencies = [
|
|||||||
{ name = "uv" },
|
{ name = "uv" },
|
||||||
{ name = "virtualenv" },
|
{ name = "virtualenv" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e4/0c/7ae1ace8d19f36624cfbbffe227169d670805f8a50a20ce65a4be14c2924/hatch-1.17.0.tar.gz", hash = "sha256:2bbbf4aa8f6fda71a61fc24c22619261327b53d272b22d4cc16f4a6e9a8592bb", size = 5250272, upload-time = "2026-06-02T00:11:58.603Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/10/fd/634c575b5becad2dfa7135f3ad66d57102cd77d834cf473756d868a808ff/hatch-1.18.0.tar.gz", hash = "sha256:463d214cb068391454be198e58d3cc0846f71e39d68c5568ba650af7781e8ae3", size = 5275084, upload-time = "2026-08-11T05:06:41.513Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/e4/bd/0a7f877ec78e6910868e39a68c2a1964fa0737a4008ee1f3fd7e2fd8915f/hatch-1.17.0-py3-none-any.whl", hash = "sha256:cb742cc9113085c7dc88fde5a54e594846d8395102ae86e32179d5e72ff3c589", size = 161751, upload-time = "2026-06-02T00:11:56.922Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/b1/d14265cb26c57af1485c01fd95037a35f13748b718617405cdefc6150429/hatch-1.18.0-py3-none-any.whl", hash = "sha256:75874c0905fe76b44fd39585c49bc9bd2b9fee638abb11f1f3d087042e7f9122", size = 171310, upload-time = "2026-08-11T05:06:39.807Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -742,15 +737,15 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpcore2"
|
name = "httpcore2"
|
||||||
version = "2.5.0"
|
version = "2.12.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "h11" },
|
{ name = "h11" },
|
||||||
{ name = "truststore" },
|
{ name = "truststore" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/47/06/5c12df521b5322fb1114a83d46911b2fbcb8855ddb3a635f11c01a214af5/httpcore2-2.5.0.tar.gz", hash = "sha256:88aa170137c17328d5ac44234f9fd10706466d5fb347f3edac4d39b91137b09d", size = 64808, upload-time = "2026-06-25T14:16:56.472Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/be/ad/f4f0e57345f1870f3e8cb624e058d7eca6e5a27d33bcc3311d9b618734cd/httpcore2-2.12.0.tar.gz", hash = "sha256:9293522bba0aa7c4c8e9e3f040c16575bd8868e155a77fa30c7a9085a5eae648", size = 67548, upload-time = "2026-08-18T13:22:08.211Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/c9/a1/7564199d1a8728fe737b0a72e5b3f8d92dfe085a74ddf7cdd83bce5f206d/httpcore2-2.5.0-py3-none-any.whl", hash = "sha256:5ce35188de461d31e8d000bfb8ef8bf22c6c16587a211e5571deaa5e9bdf842a", size = 80330, upload-time = "2026-06-25T14:16:53.634Z" },
|
{ url = "https://files.pythonhosted.org/packages/d2/74/d370e55600d9bcfa0d9794b0166126d49291a3d2b20c268fc98c453a4948/httpcore2-2.12.0-py3-none-any.whl", hash = "sha256:7e04258ce01013d7d615e5b910a3b27fac937d7a95038227e79652b4ba3b4ceb", size = 83074, upload-time = "2026-08-18T13:22:05.854Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -808,18 +803,28 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "httpx2"
|
name = "httpx2"
|
||||||
version = "2.5.0"
|
version = "2.12.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio" },
|
{ name = "anyio", marker = "sys_platform != 'emscripten'" },
|
||||||
{ name = "httpcore2" },
|
{ name = "httpcore2", marker = "sys_platform != 'emscripten'" },
|
||||||
|
{ name = "httpx2-jsfetch", marker = "python_full_version >= '3.12' and sys_platform == 'emscripten'" },
|
||||||
{ name = "idna" },
|
{ name = "idna" },
|
||||||
{ name = "truststore" },
|
{ name = "truststore", marker = "sys_platform != 'emscripten'" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/d0/e2/b5dedc0cf35aa65de5f541ccd30d2bc1fd7f1d43c9ab09f8ed9a7342317b/httpx2-2.5.0.tar.gz", hash = "sha256:e2df9cb4611021527ff8a675b1c320b610a2ec397acc8d6fe6e91df2d9b33c29", size = 83121, upload-time = "2026-06-25T14:16:57.491Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/7f/f8/579a8b51e42e38ee32647df9f08aa25643ae788e275cc625b199829c4671/httpx2-2.12.0.tar.gz", hash = "sha256:7631fe9887a8a2275f4a2540e053aa670fcc50742864a9ae7c66e609fdcf12cf", size = 100040, upload-time = "2026-08-18T13:22:09.086Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/31/22/859d8252dad9bc9adee34b52e62cde621ece07b042ccb2ab4da1be46695f/httpx2-2.5.0-py3-none-any.whl", hash = "sha256:3d2d4d9cf4b61f1a1f46a95947cfdb47e80cb56a2f91c6256ac8f58e4891df41", size = 76652, upload-time = "2026-06-25T14:16:55.23Z" },
|
{ url = "https://files.pythonhosted.org/packages/c8/95/411ba65569158e862368917aaf56597f3e5fa3b91b0502919638465a08f3/httpx2-2.12.0-py3-none-any.whl", hash = "sha256:cc8b6eecb8661c146b8f89a60e97456ee086e91a784ed31ac450c3a9e613dd36", size = 95427, upload-time = "2026-08-18T13:22:06.834Z" },
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "httpx2-jsfetch"
|
||||||
|
version = "1.0"
|
||||||
|
source = { registry = "https://pypi.org/simple" }
|
||||||
|
sdist = { url = "https://files.pythonhosted.org/packages/cd/c4/0e5636363151a2a1795e0a77617168b9ca438e1748ec05fc9b5687f93d64/httpx2_jsfetch-1.0.tar.gz", hash = "sha256:70a0e3eabfef7cce5ad9c629f7d01ca05e418f586646f4ddf14782e4c1454c60", size = 6872, upload-time = "2026-08-07T00:13:07.492Z" }
|
||||||
|
wheels = [
|
||||||
|
{ url = "https://files.pythonhosted.org/packages/9b/43/832f631d32e4f1211caa2ba368317739fe71f0b8530e4c9d15dc454bac2a/httpx2_jsfetch-1.0-py3-none-any.whl", hash = "sha256:cb916b707601e69a07721aabc8f3f6659be3a6893bc1ff5c6f9e02241df2da32", size = 6382, upload-time = "2026-08-07T00:13:06.567Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -914,7 +919,7 @@ name = "jsonpatch"
|
|||||||
version = "1.33"
|
version = "1.33"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpointer", marker = "python_full_version >= '3.11'" },
|
{ name = "jsonpointer" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/42/78/18813351fe5d63acad16aec57f94ec2b70a09e53ca98145589e185423873/jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c", size = 21699, upload-time = "2023-06-26T12:07:29.144Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -988,15 +993,15 @@ name = "langchain-core"
|
|||||||
version = "1.4.0"
|
version = "1.4.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "jsonpatch", marker = "python_full_version >= '3.11'" },
|
{ name = "jsonpatch" },
|
||||||
{ name = "langchain-protocol", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "langsmith", marker = "python_full_version >= '3.11'" },
|
{ name = "langsmith" },
|
||||||
{ name = "packaging", marker = "python_full_version >= '3.11'" },
|
{ name = "packaging" },
|
||||||
{ name = "pydantic", marker = "python_full_version >= '3.11'" },
|
{ name = "pydantic" },
|
||||||
{ name = "pyyaml", marker = "python_full_version >= '3.11'" },
|
{ name = "pyyaml" },
|
||||||
{ name = "tenacity", marker = "python_full_version >= '3.11'" },
|
{ name = "tenacity" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "uuid-utils", marker = "python_full_version >= '3.11'" },
|
{ name = "uuid-utils" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/59/de/679a53472c25860837e32c0442c962fa86e95317a36460e2c9d5c91b17c2/langchain_core-1.4.0.tar.gz", hash = "sha256:1dc341eed802ed9c117c0df3923c991e5e9e226571e5725c194eeb5bd93d1a7f", size = 920260, upload-time = "2026-05-11T18:42:35.919Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/59/de/679a53472c25860837e32c0442c962fa86e95317a36460e2c9d5c91b17c2/langchain_core-1.4.0.tar.gz", hash = "sha256:1dc341eed802ed9c117c0df3923c991e5e9e226571e5725c194eeb5bd93d1a7f", size = 920260, upload-time = "2026-05-11T18:42:35.919Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1008,7 +1013,7 @@ name = "langchain-protocol"
|
|||||||
version = "0.0.17"
|
version = "0.0.17"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/44/b3/4e2429876c7a35585618caa2b9f9089f7162a6b50562b614ad82ac11c17e/langchain_protocol-0.0.17.tar.gz", hash = "sha256:e7cbe58c205df4b4fd87dc6d5bb23f10e13b236d0e2e1b0b9d05bc2b648f3eea", size = 6026, upload-time = "2026-06-12T18:39:51.923Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/44/b3/4e2429876c7a35585618caa2b9f9089f7162a6b50562b614ad82ac11c17e/langchain_protocol-0.0.17.tar.gz", hash = "sha256:e7cbe58c205df4b4fd87dc6d5bb23f10e13b236d0e2e1b0b9d05bc2b648f3eea", size = 6026, upload-time = "2026-06-12T18:39:51.923Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1020,12 +1025,12 @@ name = "langgraph"
|
|||||||
version = "1.2.3"
|
version = "1.2.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-core" },
|
||||||
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-checkpoint" },
|
||||||
{ name = "langgraph-prebuilt", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-prebuilt" },
|
||||||
{ name = "langgraph-sdk", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-sdk" },
|
||||||
{ name = "pydantic", marker = "python_full_version >= '3.11'" },
|
{ name = "pydantic" },
|
||||||
{ name = "xxhash", marker = "python_full_version >= '3.11'" },
|
{ name = "xxhash" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/5c/55/e42f59b5e4cce75085f68abb77114c4d1152628157bd60c2587881bca559/langgraph-1.2.3.tar.gz", hash = "sha256:7f89cd5f0946fe29bd7ca048e2a84d3c14e7f652e38bb98e00f0ba8b7004b9d0", size = 718812, upload-time = "2026-06-01T18:55:54.458Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/5c/55/e42f59b5e4cce75085f68abb77114c4d1152628157bd60c2587881bca559/langgraph-1.2.3.tar.gz", hash = "sha256:7f89cd5f0946fe29bd7ca048e2a84d3c14e7f652e38bb98e00f0ba8b7004b9d0", size = 718812, upload-time = "2026-06-01T18:55:54.458Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1037,38 +1042,38 @@ name = "langgraph-api"
|
|||||||
version = "0.10.0"
|
version = "0.10.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "cloudpickle", marker = "python_full_version >= '3.11'" },
|
{ name = "cloudpickle" },
|
||||||
{ name = "cryptography", marker = "python_full_version >= '3.11'" },
|
{ name = "cryptography" },
|
||||||
{ name = "grpcio", marker = "python_full_version >= '3.11'" },
|
{ name = "grpcio" },
|
||||||
{ name = "grpcio-health-checking", marker = "python_full_version >= '3.11'" },
|
{ name = "grpcio-health-checking" },
|
||||||
{ name = "grpcio-tools", marker = "python_full_version >= '3.11'" },
|
{ name = "grpcio-tools" },
|
||||||
{ name = "httptools", marker = "python_full_version >= '3.11' and sys_platform != 'win32'" },
|
{ name = "httptools", marker = "sys_platform != 'win32'" },
|
||||||
{ name = "httpx", marker = "python_full_version >= '3.11'" },
|
{ name = "httpx" },
|
||||||
{ name = "jsonschema-rs", marker = "python_full_version >= '3.11'" },
|
{ name = "jsonschema-rs" },
|
||||||
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-core" },
|
||||||
{ name = "langchain-protocol", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "langgraph", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph" },
|
||||||
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-checkpoint" },
|
||||||
{ name = "langgraph-runtime-inmem", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-runtime-inmem" },
|
||||||
{ name = "langgraph-sdk", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-sdk" },
|
||||||
{ name = "langsmith", extra = ["otel"], marker = "python_full_version >= '3.11'" },
|
{ name = "langsmith", extra = ["otel"] },
|
||||||
{ name = "opentelemetry-api", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "opentelemetry-exporter-otlp-proto-http", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-exporter-otlp-proto-http" },
|
||||||
{ name = "opentelemetry-sdk", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-sdk" },
|
||||||
{ name = "orjson", marker = "python_full_version >= '3.11'" },
|
{ name = "orjson" },
|
||||||
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
|
{ name = "protobuf" },
|
||||||
{ name = "pyjwt", marker = "python_full_version >= '3.11'" },
|
{ name = "pyjwt" },
|
||||||
{ name = "sse-starlette", marker = "python_full_version >= '3.11'" },
|
{ name = "sse-starlette" },
|
||||||
{ name = "starlette", marker = "python_full_version >= '3.11'" },
|
{ name = "starlette" },
|
||||||
{ name = "structlog", marker = "python_full_version >= '3.11'" },
|
{ name = "structlog" },
|
||||||
{ name = "tenacity", marker = "python_full_version >= '3.11'" },
|
{ name = "tenacity" },
|
||||||
{ name = "truststore", marker = "python_full_version >= '3.11'" },
|
{ name = "truststore" },
|
||||||
{ name = "uuid-utils", marker = "python_full_version >= '3.11'" },
|
{ name = "uuid-utils" },
|
||||||
{ name = "uvicorn", marker = "python_full_version >= '3.11'" },
|
{ name = "uvicorn" },
|
||||||
{ name = "uvloop", marker = "python_full_version >= '3.11' and sys_platform != 'win32'" },
|
{ name = "uvloop", marker = "sys_platform != 'win32'" },
|
||||||
{ name = "watchfiles", marker = "python_full_version >= '3.11'" },
|
{ name = "watchfiles" },
|
||||||
{ name = "websockets", marker = "python_full_version >= '3.11'" },
|
{ name = "websockets" },
|
||||||
{ name = "zstandard", marker = "python_full_version >= '3.11'" },
|
{ name = "zstandard" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/7d/17/a23ecdad3de7e48209bc8d534312ba83e332126ec60da9e6487461b02597/langgraph_api-0.10.0.tar.gz", hash = "sha256:f594a160857e2cd7fb2352bba585111177a4a394625ad0cf5898814754fb7bc1", size = 713903, upload-time = "2026-06-11T14:36:50.469Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/7d/17/a23ecdad3de7e48209bc8d534312ba83e332126ec60da9e6487461b02597/langgraph_api-0.10.0.tar.gz", hash = "sha256:f594a160857e2cd7fb2352bba585111177a4a394625ad0cf5898814754fb7bc1", size = 713903, upload-time = "2026-06-11T14:36:50.469Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1080,8 +1085,8 @@ name = "langgraph-checkpoint"
|
|||||||
version = "4.1.1"
|
version = "4.1.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-core" },
|
||||||
{ name = "ormsgpack", marker = "python_full_version >= '3.11'" },
|
{ name = "ormsgpack" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/83/47/886af6f886f0bff2273164a45f008694e48a96ff3cd25ff0228f2aa9480e/langgraph_checkpoint-4.1.1.tar.gz", hash = "sha256:6c2bdb530c91f91d7d9c1bd100925d0fc4f498d418c17f3587d1526279482a25", size = 184020, upload-time = "2026-05-22T16:57:38.503Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/83/47/886af6f886f0bff2273164a45f008694e48a96ff3cd25ff0228f2aa9480e/langgraph_checkpoint-4.1.1.tar.gz", hash = "sha256:6c2bdb530c91f91d7d9c1bd100925d0fc4f498d418c17f3587d1526279482a25", size = 184020, upload-time = "2026-05-22T16:57:38.503Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1174,8 +1179,8 @@ name = "langgraph-prebuilt"
|
|||||||
version = "1.1.0"
|
version = "1.1.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-core" },
|
||||||
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-checkpoint" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/29/66/ed9b93f56bc17ef22d551892f0ac2b225a97fe0fcf23a511b857f70d590b/langgraph_prebuilt-1.1.0.tar.gz", hash = "sha256:3c579cf6eed2d17f9c157c2d0fcaddcd8688524e7022d3b22b37a3bf4589d528", size = 178833, upload-time = "2026-05-12T03:37:49.332Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/29/66/ed9b93f56bc17ef22d551892f0ac2b225a97fe0fcf23a511b857f70d590b/langgraph_prebuilt-1.1.0.tar.gz", hash = "sha256:3c579cf6eed2d17f9c157c2d0fcaddcd8688524e7022d3b22b37a3bf4589d528", size = 178833, upload-time = "2026-05-12T03:37:49.332Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1187,13 +1192,13 @@ name = "langgraph-runtime-inmem"
|
|||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "blockbuster", marker = "python_full_version >= '3.11'" },
|
{ name = "blockbuster" },
|
||||||
{ name = "croniter", marker = "python_full_version >= '3.11'" },
|
{ name = "croniter" },
|
||||||
{ name = "langgraph", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph" },
|
||||||
{ name = "langgraph-checkpoint", marker = "python_full_version >= '3.11'" },
|
{ name = "langgraph-checkpoint" },
|
||||||
{ name = "sse-starlette", marker = "python_full_version >= '3.11'" },
|
{ name = "sse-starlette" },
|
||||||
{ name = "starlette", marker = "python_full_version >= '3.11'" },
|
{ name = "starlette" },
|
||||||
{ name = "structlog", marker = "python_full_version >= '3.11'" },
|
{ name = "structlog" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/98/19/5d330e22e3ee2569742d3577b4ddfbb6b8e383f2edd9724b4a4b73735717/langgraph_runtime_inmem-0.30.0.tar.gz", hash = "sha256:31954e1de6cd43c284b425243d4faeae818f68b3daca4dbe4313e651b6f5e11d", size = 129940, upload-time = "2026-06-11T14:22:46.985Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/98/19/5d330e22e3ee2569742d3577b4ddfbb6b8e383f2edd9724b4a4b73735717/langgraph_runtime_inmem-0.30.0.tar.gz", hash = "sha256:31954e1de6cd43c284b425243d4faeae818f68b3daca4dbe4313e651b6f5e11d", size = 129940, upload-time = "2026-06-11T14:22:46.985Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1202,18 +1207,18 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "langgraph-sdk"
|
name = "langgraph-sdk"
|
||||||
version = "0.4.2"
|
version = "0.4.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "httpx", marker = "python_full_version >= '3.11'" },
|
{ name = "httpx" },
|
||||||
{ name = "langchain-core", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-core" },
|
||||||
{ name = "langchain-protocol", marker = "python_full_version >= '3.11'" },
|
{ name = "langchain-protocol" },
|
||||||
{ name = "orjson", marker = "python_full_version >= '3.11'" },
|
{ name = "orjson" },
|
||||||
{ name = "websockets", marker = "python_full_version >= '3.11'" },
|
{ name = "websockets" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/b4/2b/bd8ac26d4e97f6df88ef05ce5b6a38945a3903e1025d926f4752aa88aa97/langgraph_sdk-0.4.2.tar.gz", hash = "sha256:b88f0f5f6328ac0680d6790614a905b2bcfa257f2276dba4e38f0e86db0aa738", size = 348327, upload-time = "2026-06-01T17:51:19.856Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/3f/ae/91446c1fffa04a2dc1f81afbfb5bfff3590452891a72bd9098a656ab2657/langgraph_sdk-0.4.4.tar.gz", hash = "sha256:4e651ffa09de695681579396375377bdde23bedbc8e35b070e615cbd5af7da8b", size = 345789, upload-time = "2026-08-27T21:25:22.593Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/a0/05/aac507337cceae773c2cc9ab91eb6301963af7aeeb55b4217a00e15aff17/langgraph_sdk-0.4.2-py3-none-any.whl", hash = "sha256:75fa5096c1177ce39c847096a8fe3745ffd480ddb412995f836e9f5f884c43dd", size = 160521, upload-time = "2026-06-01T17:51:18.849Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/d5/2ad7f3a835c6fcebf58b6669552536ecd52d2dfe4cf49c6c36648fd83572/langgraph_sdk-0.4.4-py3-none-any.whl", hash = "sha256:39afe416c91742925e6f8a93715f566d499b36e1b636b804a4ffe3190e4f4e64", size = 162270, upload-time = "2026-08-27T21:25:21.072Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1221,16 +1226,16 @@ name = "langsmith"
|
|||||||
version = "0.8.18"
|
version = "0.8.18"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "httpx", marker = "python_full_version >= '3.11'" },
|
{ name = "httpx" },
|
||||||
{ name = "orjson", marker = "python_full_version >= '3.11' and platform_python_implementation != 'PyPy'" },
|
{ name = "orjson", marker = "platform_python_implementation != 'PyPy'" },
|
||||||
{ name = "packaging", marker = "python_full_version >= '3.11'" },
|
{ name = "packaging" },
|
||||||
{ name = "pydantic", marker = "python_full_version >= '3.11'" },
|
{ name = "pydantic" },
|
||||||
{ name = "requests", marker = "python_full_version >= '3.11'" },
|
{ name = "requests" },
|
||||||
{ name = "requests-toolbelt", marker = "python_full_version >= '3.11'" },
|
{ name = "requests-toolbelt" },
|
||||||
{ name = "uuid-utils", marker = "python_full_version >= '3.11'" },
|
{ name = "uuid-utils" },
|
||||||
{ name = "websockets", marker = "python_full_version >= '3.11'" },
|
{ name = "websockets" },
|
||||||
{ name = "xxhash", marker = "python_full_version >= '3.11'" },
|
{ name = "xxhash" },
|
||||||
{ name = "zstandard", marker = "python_full_version >= '3.11'" },
|
{ name = "zstandard" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/9a/d9/a6681aa9847bbbc5ec21abe20a5e233b94e5edcfe39624db607ac7e8ccb4/langsmith-0.8.18.tar.gz", hash = "sha256:32dde9c0e67e053e0fb738921fc8ced768af7b8fa83d7a0e3fd63597cf8776dd", size = 4526988, upload-time = "2026-06-19T13:12:17.123Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1239,9 +1244,9 @@ wheels = [
|
|||||||
|
|
||||||
[package.optional-dependencies]
|
[package.optional-dependencies]
|
||||||
otel = [
|
otel = [
|
||||||
{ name = "opentelemetry-api", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "opentelemetry-exporter-otlp-proto-http", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-exporter-otlp-proto-http" },
|
||||||
{ name = "opentelemetry-sdk", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-sdk" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1335,8 +1340,8 @@ name = "opentelemetry-api"
|
|||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "importlib-metadata", marker = "python_full_version >= '3.11'" },
|
{ name = "importlib-metadata" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/47/8e/3778a7e87801d994869a9396b9fc2a289e5f9be91ff54a27d41eace494b0/opentelemetry_api-1.41.0.tar.gz", hash = "sha256:9421d911326ec12dee8bc933f7839090cad7a3f13fcfb0f9e82f8174dc003c09", size = 71416, upload-time = "2026-04-09T14:38:34.544Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/47/8e/3778a7e87801d994869a9396b9fc2a289e5f9be91ff54a27d41eace494b0/opentelemetry_api-1.41.0.tar.gz", hash = "sha256:9421d911326ec12dee8bc933f7839090cad7a3f13fcfb0f9e82f8174dc003c09", size = 71416, upload-time = "2026-04-09T14:38:34.544Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1348,7 +1353,7 @@ name = "opentelemetry-exporter-otlp-proto-common"
|
|||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "opentelemetry-proto", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-proto" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/28/e8eca94966fe9a1465f6094dc5ddc5398473682180279c94020bc23b4906/opentelemetry_exporter_otlp_proto_common-1.41.0.tar.gz", hash = "sha256:966bbce537e9edb166154779a7c4f8ab6b8654a03a28024aeaf1a3eacb07d6ee", size = 20411, upload-time = "2026-04-09T14:38:36.572Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/8c/28/e8eca94966fe9a1465f6094dc5ddc5398473682180279c94020bc23b4906/opentelemetry_exporter_otlp_proto_common-1.41.0.tar.gz", hash = "sha256:966bbce537e9edb166154779a7c4f8ab6b8654a03a28024aeaf1a3eacb07d6ee", size = 20411, upload-time = "2026-04-09T14:38:36.572Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1360,13 +1365,13 @@ name = "opentelemetry-exporter-otlp-proto-http"
|
|||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "googleapis-common-protos", marker = "python_full_version >= '3.11'" },
|
{ name = "googleapis-common-protos" },
|
||||||
{ name = "opentelemetry-api", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "opentelemetry-exporter-otlp-proto-common", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-exporter-otlp-proto-common" },
|
||||||
{ name = "opentelemetry-proto", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-proto" },
|
||||||
{ name = "opentelemetry-sdk", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-sdk" },
|
||||||
{ name = "requests", marker = "python_full_version >= '3.11'" },
|
{ name = "requests" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/19/63/d9f43cd75f3fabb7e01148c89cfa9491fc18f6580a6764c554ff7c953c46/opentelemetry_exporter_otlp_proto_http-1.41.0.tar.gz", hash = "sha256:dcd6e0686f56277db4eecbadd5262124e8f2cc739cadbc3fae3d08a12c976cf5", size = 24139, upload-time = "2026-04-09T14:38:38.128Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/19/63/d9f43cd75f3fabb7e01148c89cfa9491fc18f6580a6764c554ff7c953c46/opentelemetry_exporter_otlp_proto_http-1.41.0.tar.gz", hash = "sha256:dcd6e0686f56277db4eecbadd5262124e8f2cc739cadbc3fae3d08a12c976cf5", size = 24139, upload-time = "2026-04-09T14:38:38.128Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1378,7 +1383,7 @@ name = "opentelemetry-proto"
|
|||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "protobuf", marker = "python_full_version >= '3.11'" },
|
{ name = "protobuf" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/e0/d9/08e3dc6156878713e8c811682bc76151f5fe1a3cb7f3abda3966fd56e71e/opentelemetry_proto-1.41.0.tar.gz", hash = "sha256:95d2e576f9fb1800473a3e4cfcca054295d06bdb869fda4dc9f4f779dc68f7b6", size = 45669, upload-time = "2026-04-09T14:38:45.978Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/e0/d9/08e3dc6156878713e8c811682bc76151f5fe1a3cb7f3abda3966fd56e71e/opentelemetry_proto-1.41.0.tar.gz", hash = "sha256:95d2e576f9fb1800473a3e4cfcca054295d06bdb869fda4dc9f4f779dc68f7b6", size = 45669, upload-time = "2026-04-09T14:38:45.978Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1390,9 +1395,9 @@ name = "opentelemetry-sdk"
|
|||||||
version = "1.41.0"
|
version = "1.41.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "opentelemetry-api", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "opentelemetry-semantic-conventions", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-semantic-conventions" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f8/0e/a586df1186f9f56b5a0879d52653effc40357b8e88fc50fe300038c3c08b/opentelemetry_sdk-1.41.0.tar.gz", hash = "sha256:7bddf3961131b318fc2d158947971a8e37e38b1cd23470cfb72b624e7cc108bd", size = 230181, upload-time = "2026-04-09T14:38:47.225Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f8/0e/a586df1186f9f56b5a0879d52653effc40357b8e88fc50fe300038c3c08b/opentelemetry_sdk-1.41.0.tar.gz", hash = "sha256:7bddf3961131b318fc2d158947971a8e37e38b1cd23470cfb72b624e7cc108bd", size = 230181, upload-time = "2026-04-09T14:38:47.225Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1404,8 +1409,8 @@ name = "opentelemetry-semantic-conventions"
|
|||||||
version = "0.62b0"
|
version = "0.62b0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "opentelemetry-api", marker = "python_full_version >= '3.11'" },
|
{ name = "opentelemetry-api" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/a3/b0/c14f723e86c049b7bf8ff431160d982519b97a7be2857ed2247377397a24/opentelemetry_semantic_conventions-0.62b0.tar.gz", hash = "sha256:cbfb3c8fc259575cf68a6e1b94083cc35adc4a6b06e8cf431efa0d62606c0097", size = 145753, upload-time = "2026-04-09T14:38:48.274Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/a3/b0/c14f723e86c049b7bf8ff431160d982519b97a7be2857ed2247377397a24/opentelemetry_semantic_conventions-0.62b0.tar.gz", hash = "sha256:cbfb3c8fc259575cf68a6e1b94083cc35adc4a6b06e8cf431efa0d62606c0097", size = 145753, upload-time = "2026-04-09T14:38:48.274Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1635,10 +1640,10 @@ name = "pydantic"
|
|||||||
version = "2.13.2"
|
version = "2.13.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "annotated-types", marker = "python_full_version >= '3.11'" },
|
{ name = "annotated-types" },
|
||||||
{ name = "pydantic-core", marker = "python_full_version >= '3.11'" },
|
{ name = "pydantic-core" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
{ name = "typing-inspection", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-inspection" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/09/e5/06d23afac9973109d1e3c8ad38e1547a12e860610e327c05ee686827dc37/pydantic-2.13.2.tar.gz", hash = "sha256:b418196607e61081c3226dcd4f0672f2a194828abb9109e9cfb84026564df2d1", size = 843836, upload-time = "2026-04-17T09:31:59.636Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/09/e5/06d23afac9973109d1e3c8ad38e1547a12e860610e327c05ee686827dc37/pydantic-2.13.2.tar.gz", hash = "sha256:b418196607e61081c3226dcd4f0672f2a194828abb9109e9cfb84026564df2d1", size = 843836, upload-time = "2026-04-17T09:31:59.636Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1650,7 +1655,7 @@ name = "pydantic-core"
|
|||||||
version = "2.46.2"
|
version = "2.46.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/bb/4742f05b739b2478459bb16fa8470549518c802e06ddcf3f106c5081315e/pydantic_core-2.46.2.tar.gz", hash = "sha256:37bb079f9ee3f1a519392b73fda2a96379b31f2013c6b467fe693e7f2987f596", size = 471269, upload-time = "2026-04-17T09:10:07.017Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/43/bb/4742f05b739b2478459bb16fa8470549518c802e06ddcf3f106c5081315e/pydantic_core-2.46.2.tar.gz", hash = "sha256:37bb079f9ee3f1a519392b73fda2a96379b31f2013c6b467fe693e7f2987f596", size = 471269, upload-time = "2026-04-17T09:10:07.017Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1849,7 +1854,7 @@ name = "python-dateutil"
|
|||||||
version = "2.9.0.post0"
|
version = "2.9.0.post0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "six", marker = "python_full_version >= '3.11'" },
|
{ name = "six" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1871,11 +1876,11 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "python-dotenv"
|
name = "python-dotenv"
|
||||||
version = "1.2.2"
|
version = "1.2.3"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/6a/53/ed9d74092561d4b01a2ef1349d52cdbc135e526c245f366b089cfca6de49/python_dotenv-1.2.3.tar.gz", hash = "sha256:a20a594dabeaa385725aa239d5244871c143ecb356add8a20fcf23773a6c3a35", size = 58945, upload-time = "2026-08-16T16:54:54.067Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" },
|
{ url = "https://files.pythonhosted.org/packages/0d/17/c5c6b53ddc18f297992099b3d9ec16c855c0ccc83263a21fe4d1c625ec6c/python_dotenv-1.2.3-py3-none-any.whl", hash = "sha256:904552145e8bfed22162c09dab1c2b9b54fefa7b23ba780f4f26ca0316b0f0d9", size = 22780, upload-time = "2026-08-16T16:54:52.473Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -1956,10 +1961,10 @@ name = "requests"
|
|||||||
version = "2.33.1"
|
version = "2.33.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "certifi", marker = "python_full_version >= '3.11'" },
|
{ name = "certifi" },
|
||||||
{ name = "charset-normalizer", marker = "python_full_version >= '3.11'" },
|
{ name = "charset-normalizer" },
|
||||||
{ name = "idna", marker = "python_full_version >= '3.11'" },
|
{ name = "idna" },
|
||||||
{ name = "urllib3", marker = "python_full_version >= '3.11'" },
|
{ name = "urllib3" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/5f/a4/98b9c7c6428a668bf7e42ebb7c79d576a1c3c1e3ae2d47e674b468388871/requests-2.33.1.tar.gz", hash = "sha256:18817f8c57c6263968bc123d237e3b8b08ac046f5456bd1e307ee8f4250d3517", size = 134120, upload-time = "2026-03-30T16:09:15.531Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1971,7 +1976,7 @@ name = "requests-toolbelt"
|
|||||||
version = "1.0.0"
|
version = "1.0.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "requests", marker = "python_full_version >= '3.11'" },
|
{ name = "requests" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6", size = 206888, upload-time = "2023-05-01T04:11:33.229Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -1993,27 +1998,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ruff"
|
name = "ruff"
|
||||||
version = "0.15.20"
|
version = "0.16.5"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/43/dc/35b341fc554ba02f217fc10da57d1a75168cfbcf75b0ef2202176d4c4f2d/ruff-0.15.20.tar.gz", hash = "sha256:1416eb04349192646b54de98f146c4f59afe37d0decfc02c3cbbf396f3a28566", size = 4755489, upload-time = "2026-06-25T17:20:37.578Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/f3/85/c8e12473c93018f92d19dd988a294202e1c27426c47ec4de53ffb847b8d8/ruff-0.16.5.tar.gz", hash = "sha256:1b88500f9ffbcab3dedb0082c9f9492e91ec3d618aac1236a3e0189938f7040b", size = 4912003, upload-time = "2026-08-27T16:34:18.258Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/94/d9/2d5014f0253ba541d2061d9fa7193f48e941c8b21bb88a7ff9bbe0bd0596/ruff-0.15.20-py3-none-linux_armv6l.whl", hash = "sha256:00e188c53e499c3c1637f73c91dcf2fb56d576cab76ce1be50a27c4e80e37078", size = 10839665, upload-time = "2026-06-25T17:19:44.702Z" },
|
{ url = "https://files.pythonhosted.org/packages/c6/b6/77c90a970fe2dae17a723acbd011043ea97c98d7deacccefdc4ba74ec512/ruff-0.16.5-py3-none-linux_armv6l.whl", hash = "sha256:12e5f673e774c35fbb62f288809c7653b73445f8ecec6b6063fd6ea3521aa14b", size = 10011941, upload-time = "2026-08-27T16:33:41.287Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/c6/d3/ac1798ba64f670698867fcfc591d50e7e421bef137db564858f619a30fcf/ruff-0.15.20-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:9ebd1fd9b9c95fc0bd7b2761aebec1f030013d2e193a2901b224af68fe47251b", size = 11208649, upload-time = "2026-06-25T17:19:48.787Z" },
|
{ url = "https://files.pythonhosted.org/packages/4b/46/6cf67cf6411885a1d6f7f6d801682f155536a85176d10b605e2ceffed8bd/ruff-0.16.5-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:eda58a5802de40e7ed5b32b64e0b32539338cc6fcd2c78f61e3ad6a0d79f51c3", size = 10204049, upload-time = "2026-08-27T16:33:44.056Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/47/47/d3ac899991202095dfcf3d5176be4272642be3cf981a2f1a30f72a2afb95/ruff-0.15.20-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5b16cdd67ca108185cd36dce98c576350c03b1660a751de725fb049193a0632", size = 10622638, upload-time = "2026-06-25T17:19:51.354Z" },
|
{ url = "https://files.pythonhosted.org/packages/46/fd/c8720ca7a090abf0c2fef4abe8a5ef6e5127ed15196d8886ff75a2b370e2/ruff-0.16.5-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c5ae9a7b9a8875131f40f8fe967cc86abf899779efd663cb7ce3d572d01da7eb", size = 9809037, upload-time = "2026-08-27T16:33:46.257Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/33/13/4e043fe30aa94d4ff5213a9881fc296d12960f5971b234a5263fdc225312/ruff-0.15.20-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3413bb3c3d2ca6a8208f1f4809cd2dca3c6de6d0b491c0e70847672bde6e6efd", size = 10984227, upload-time = "2026-06-25T17:19:54.044Z" },
|
{ url = "https://files.pythonhosted.org/packages/43/45/a684caacdedaca180f52bacccc40bf0789d2c5a7c75f25324853e9eaedb5/ruff-0.16.5-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b719b0a1f4d59710d283ab2965f621684a108a9e41da622e3b23f0326cd0025", size = 9964129, upload-time = "2026-08-27T16:33:48.352Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/76/e6/92e7bf40388bc5800073b96564f56264f7e48bfd1a498f5ced6ae6d5a769/ruff-0.15.20-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bd7ec42b3bb3da066488db093308a69c4ac5ee6d2af333a86ba6e2eb2e7dd44b", size = 10622882, upload-time = "2026-06-25T17:19:57.037Z" },
|
{ url = "https://files.pythonhosted.org/packages/9e/f2/5d2bcdaca6b5b93d1b4dfc166cd2aebf7680143a1b38a28759df13a94d31/ruff-0.16.5-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2298f2780ed1be0c5cb1361e32ab7b1467f3cce7dabe101d2210a314f2fe42e9", size = 9821518, upload-time = "2026-08-27T16:33:50.57Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/13/7a/43460be3f24495a3aa46d4b16873e2c4941b3b5f0b00cf88c03b7b94b339/ruff-0.15.20-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e1a36ad0eb77fba9aabfb69ede54de6f376d04ac18ebea022847046d340a8267", size = 11474808, upload-time = "2026-06-25T17:20:00.357Z" },
|
{ url = "https://files.pythonhosted.org/packages/aa/ff/011cce29accf9257d5974145b733fc653a37985ed6825413a3987cefbfe0/ruff-0.16.5-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:258f29035a2dd021e7861e631b227a5b3f14e50c1184c9a6a122c5f4576154d7", size = 10534835, upload-time = "2026-08-27T16:33:52.522Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/27/a0/f37077884873221c6b33b4ab49eb18f9f88e54a16a25a5bca59bef46dd66/ruff-0.15.20-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b6df3b1e4610432f0386dba04d853b5f08cbbc903410c6fcc02f620f05aff53c", size = 12293094, upload-time = "2026-06-25T17:20:03.446Z" },
|
{ url = "https://files.pythonhosted.org/packages/d7/5a/f0cf109bada9bba0e96c90c21c9f9251803f57225c32d293327a03c710d6/ruff-0.16.5-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b9a4f0432966834019c74d1b7e5c51224305d7713f3d7faf3e7451f1a3be3cde", size = 11252550, upload-time = "2026-08-27T16:33:54.521Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/a6/74/165545b60256a9704c21ac0ec4a0d07933b320812f9584836c9f4aca4292/ruff-0.15.20-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e89f198a1ea6ef0d727c1cf16088bc91a6cb0ab947dedc966715691647186eae", size = 11526176, upload-time = "2026-06-25T17:20:06.301Z" },
|
{ url = "https://files.pythonhosted.org/packages/63/4d/1d481aaea2046c6a7ed7c291f9004c669cce3c087b6b376ed5b08271e3fe/ruff-0.16.5-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b5eb3a8c3d0ade9cea42b591fd530368e8798380e30e0a308b85a5cf718f09ea", size = 10777949, upload-time = "2026-08-27T16:33:56.88Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/86/b1/a976a136d40ade83ce743578399865f57001003a409acadc0ecbb3051082/ruff-0.15.20-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309809086c2acb67624950a3c8133e80f32d0d3e27106c0cd60ff26657c9f24b", size = 11520767, upload-time = "2026-06-25T17:20:09.191Z" },
|
{ url = "https://files.pythonhosted.org/packages/ee/34/ee245ca55f64443233034b3d02b03236b19242004281247c079390b7facd/ruff-0.16.5-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef0f69e191a13a3c9816f63163c88790cb12cd157bbbb384e9c44745702ab105", size = 10311656, upload-time = "2026-08-27T16:33:59.12Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/19/0f/f032696cb01c9b54c0263fa393474d7758f1cdc021a01b04e3cbc2500999/ruff-0.15.20-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:2d2374caa2f2c2f9e2b7da0a50802cfb8b79f55a9b5e49379f564544fbf56487", size = 11500132, upload-time = "2026-06-25T17:20:13.602Z" },
|
{ url = "https://files.pythonhosted.org/packages/a7/4d/c33a333e341c0a2b96c715b52d89a606f5a34cd4ac493cd9b8d0187186b8/ruff-0.16.5-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:0eeab41fbea2c42f98dfb9822cdccda9d24ba38d49f6dc945b5c236d48f0ef29", size = 10532125, upload-time = "2026-08-27T16:34:01.166Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4b/f4/51b1a14bc69e8c224b15dab9cce8e99b425e0455d462caa2b3c9be2b6a8e/ruff-0.15.20-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a1ed17b65293e0c2f22fc387bc13198a5de94bf4429589b0ff6946b0feaf21a3", size = 10943828, upload-time = "2026-06-25T17:20:16.635Z" },
|
{ url = "https://files.pythonhosted.org/packages/30/e1/a64cef78b40192497bb98a27a8aa8f2c98ee9ee15bc97f7712d94ef32937/ruff-0.16.5-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:f0768e9df4300713fff30733c87575f68b6f1d8de41184e505b7fdd9c0c95eaf", size = 10097648, upload-time = "2026-08-27T16:34:03.16Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/71/4b/fe267640783cd02bf6c5cc290b1df1051be2ec294c678b5c15fe19e52343/ruff-0.15.20-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:f701305e66b38ea6c91882490eb73459796808e4c6362a1b765255e0cdcd4053", size = 10645418, upload-time = "2026-06-25T17:20:19.4Z" },
|
{ url = "https://files.pythonhosted.org/packages/cc/4e/4cdc9ed3c3e109d2f71e62572a37457298d7bc7501ec3138babb7ed32bbd/ruff-0.16.5-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:95cc70cdc7aa80c338de356279d2adbeb2de0f520b9ecd8aba75b94e95e02f91", size = 9829344, upload-time = "2026-08-27T16:34:05.134Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b0/c0/a65aa4ec2f5e87a1df32dc3ec1fede434fe3dfd5cbcf3b503cafc676ab54/ruff-0.15.20-py3-none-musllinux_1_2_i686.whl", hash = "sha256:5b9c0c367ad8e5d0d5b5b8537864c469a0a0e55417aadfbeca41fa61333be9f4", size = 11211770, upload-time = "2026-06-25T17:20:22.033Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/4a/31ed35ce31729955fc583ee0d176d6e784c1290cb0b0a75cb2134c1ab72a/ruff-0.16.5-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d185c8398ded1bfd91c0c2cb258346307571eccc473a8490af8c3977399c384a", size = 10277117, upload-time = "2026-08-27T16:34:07.425Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/5a/a4/0caa331d954ae2723d729d351c989cb4ca8b6077d5c6c2cb6de75e98c041/ruff-0.15.20-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:01cc00dd58f0df339d0e902219dd53990ea99996a0344e5d9cc8d45d5307e460", size = 11618698, upload-time = "2026-06-25T17:20:25.259Z" },
|
{ url = "https://files.pythonhosted.org/packages/a8/a0/60356d86687b4b666d593df213f4dc3041750d024cb7bf2cfa81cfd65c2e/ruff-0.16.5-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:fb8e3a3c4c6a784150a7ced53b015f4b253fc2bf97a610886419ead64b4756ef", size = 10711653, upload-time = "2026-08-27T16:34:09.712Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/10/9b/5f14927848d2fd4aa891fd88d883788c5a7baba561c7874732364045708c/ruff-0.15.20-py3-none-win32.whl", hash = "sha256:ed65ef510e43a137207e0f01cfcf998aeddb1aeeda5c9d35023e910284d7cf21", size = 10857322, upload-time = "2026-06-25T17:20:28.612Z" },
|
{ url = "https://files.pythonhosted.org/packages/ed/20/656d67f5b25ca9bda4e02b1de25867b2954e1d19e03648060f167ad0f4cc/ruff-0.16.5-py3-none-win32.whl", hash = "sha256:288b0a5f080492fe5635db849f9e2e84aa3cce7b7f0e955997d416c507c76a26", size = 10034250, upload-time = "2026-08-27T16:34:11.8Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/fa/f0/fe47c501f9dea92a26d788ff98bb5d92ed4cb4c88792c5c88af6b697dc8e/ruff-0.15.20-py3-none-win_amd64.whl", hash = "sha256:a525c81c70fb0380344dd1d8745d8cc1c890b7fc94a58d5a07bd8eb9557b8415", size = 11993274, upload-time = "2026-06-25T17:20:31.871Z" },
|
{ url = "https://files.pythonhosted.org/packages/5b/42/ee8e68a207b9127fcde6c3d7e197def432f346cb1af159e1fa14ca0d1cdc/ruff-0.16.5-py3-none-win_amd64.whl", hash = "sha256:ddc6385fb2137f616357ca03d6c74f4be987f80fed4008566b754f6032b8546f", size = 10516714, upload-time = "2026-08-27T16:34:13.963Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/d7/2b/9555445e1201d92b3195f45cdb153a0b68f24e0a4273f6e3d5ab46e212bb/ruff-0.15.20-py3-none-win_arm64.whl", hash = "sha256:2f5b2a6d614e8700388806a14996c40fab2c47b819ef57d790a34878858ed9ca", size = 11343498, upload-time = "2026-06-25T17:20:35.03Z" },
|
{ url = "https://files.pythonhosted.org/packages/73/e3/7df5a396e445b9ba49ce9a9437439a4d80042c61c0ade199abf8d16de1ac/ruff-0.16.5-py3-none-win_arm64.whl", hash = "sha256:a64abe90968719b851bb7cedffaa8753fbdbdadab483089682db623f3edc587e", size = 10391564, upload-time = "2026-08-27T16:34:16.064Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2061,8 +2066,8 @@ name = "sse-starlette"
|
|||||||
version = "3.3.4"
|
version = "3.3.4"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio", marker = "python_full_version >= '3.11'" },
|
{ name = "anyio" },
|
||||||
{ name = "starlette", marker = "python_full_version >= '3.11'" },
|
{ name = "starlette" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/26/8c/f9290339ef6d79badbc010f067cd769d6601ec11a57d78569c683fb4dd87/sse_starlette-3.3.4.tar.gz", hash = "sha256:aaf92fc067af8a5427192895ac028e947b484ac01edbc3caf00e7e7137c7bef1", size = 32427, upload-time = "2026-03-29T09:00:23.307Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/26/8c/f9290339ef6d79badbc010f067cd769d6601ec11a57d78569c683fb4dd87/sse_starlette-3.3.4.tar.gz", hash = "sha256:aaf92fc067af8a5427192895ac028e947b484ac01edbc3caf00e7e7137c7bef1", size = 32427, upload-time = "2026-03-29T09:00:23.307Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -2074,8 +2079,8 @@ name = "starlette"
|
|||||||
version = "1.3.1"
|
version = "1.3.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio", marker = "python_full_version >= '3.11'" },
|
{ name = "anyio" },
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11' and python_full_version < '3.13'" },
|
{ name = "typing-extensions", marker = "python_full_version < '3.13'" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/eb/e3/7c1dc7381d9f8ab7d854328ebfa884e62cb3f3d8549ddfd37c7814f42afa/starlette-1.3.1.tar.gz", hash = "sha256:05d0213193f2fbaae60e2ecb593b4add4262ad4e46536b54abe36f11a71724e0", size = 2703240, upload-time = "2026-06-12T09:23:11.602Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -2192,27 +2197,27 @@ wheels = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "ty"
|
name = "ty"
|
||||||
version = "0.0.55"
|
version = "0.0.75"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/08/48/f687c8d268e3581f2f104d1f2ac5944d5b5e841b3695c613b3f263e5bbf7/ty-0.0.55.tar.gz", hash = "sha256:88ca87073825a79a8327c550efcc86cec94344890244c5946f84c9e44a969f31", size = 6040230, upload-time = "2026-06-27T00:27:29.385Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/81/d0/d0c96f898d6974a4a3569ab3efdf9512c04ad99f9203effb55f72497fe97/ty-0.0.75.tar.gz", hash = "sha256:4c5eead33dfbf6e2ebb4f400f74b51ffc9bab702a6f23ddb648a1cbb740387e3", size = 6868326, upload-time = "2026-08-26T20:23:40.399Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
{ url = "https://files.pythonhosted.org/packages/87/a3/1a90ba7e5a61c6d09adb92346ddba97668095fc257b577af433e5ac4f404/ty-0.0.55-py3-none-linux_armv6l.whl", hash = "sha256:31e83eef512d066542fe990fe1a3b814423abd1616376c54e48af7045b3e1749", size = 11677249, upload-time = "2026-06-27T00:26:52.18Z" },
|
{ url = "https://files.pythonhosted.org/packages/cb/6c/b12d03505f17581f0cfa3c12273fe34c1d67b36dfda1bc561a6bdc16512b/ty-0.0.75-py3-none-linux_armv6l.whl", hash = "sha256:e5409f50db2246fd4bd039d93d261e0cfa1daa554a4fb77256f91072c570349a", size = 12972606, upload-time = "2026-08-26T20:22:59.716Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/82/3a/669f9aa478c38243e213a2684db1502086026cfadc15bb1b29b7cbde030d/ty-0.0.55-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:ab4bca857950608fea73e269e2da369d43e6467131de85160d68e2fa466fa248", size = 11444180, upload-time = "2026-06-27T00:26:54.576Z" },
|
{ url = "https://files.pythonhosted.org/packages/d1/aa/30f11eecd9215a9f87e8fe8baaf48f3ce905f5d75b8e4aac70f0091f130c/ty-0.0.75-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5e7b8b3472fb9bb2eeab314984b265df08a7a9d518867a9e6020eebc06570be2", size = 12527158, upload-time = "2026-08-26T20:23:02.767Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/15/a4/6a4b2507a53ce6530c66c5b4fe0d58551eb1748ffa9e0696c32fdd55bbd4/ty-0.0.55-py3-none-macosx_11_0_arm64.whl", hash = "sha256:55032bfd31bf2c5355ee81bdc6407b144a1cc7ee41e5681dd1368e4cef2ba327", size = 10963134, upload-time = "2026-06-27T00:26:57.348Z" },
|
{ url = "https://files.pythonhosted.org/packages/f2/11/7fd7001b0b5c6610bfbad7357e47d5fe6f82d4e84e94c53776a478f5e9f8/ty-0.0.75-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c6ccf34169821fe0d23e3360deeef981d217963412f1d087b9bdd32ec57f7a57", size = 12400533, upload-time = "2026-08-26T20:23:04.965Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ce/ae/a3b1a0f1cc83b7d258662cb98aa80a720c2e671d0e8fa0d17a4d5d057a7a/ty-0.0.55-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ef1e049f69ce65b3c269af67624607f435e1c32319786c1e453ef9611502f295", size = 11493517, upload-time = "2026-06-27T00:26:59.26Z" },
|
{ url = "https://files.pythonhosted.org/packages/fd/7f/1e284ea3d348d7be02f12d83bc22ed9ef193033f863f05b64db99027f141/ty-0.0.75-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:842ebb41e9c6c334b40768704e20b1a69d5c6b08805b289d5e0e2565f49f2de1", size = 12420592, upload-time = "2026-08-26T20:23:07.427Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/0d/9f/311ce39065a979ef40a9b847f685c8e02464e53adf1671e081eea90640ca/ty-0.0.55-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:631409975c681d5a280fc5a99b7b32e9e801f33be7567c6b42ec331362f59d7d", size = 11460590, upload-time = "2026-06-27T00:27:01.425Z" },
|
{ url = "https://files.pythonhosted.org/packages/2d/ab/d813271543370c47fd74b5118f2066ab32b0983e907b1821f3f9a6d0fa7f/ty-0.0.75-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:cf7a5a723c5f1e0fab4ffbfe9bd95123a526ed48f206e5f25cb2161ca294007a", size = 12739219, upload-time = "2026-08-26T20:23:09.809Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/cd/8f/3bf29aa77bd78aae48275153135a2052fa7d3ccdf1ecabeb99c8773abd66/ty-0.0.55-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e08cb0436e68b9351555ae8f2697138c9009b4d5b4ae4272232988b2a431a98f", size = 12098430, upload-time = "2026-06-27T00:27:03.596Z" },
|
{ url = "https://files.pythonhosted.org/packages/31/5b/95b49cc5570fd92a7bf63732f649b31906158721e03c7fcb1b5be74ee3bf/ty-0.0.75-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:54382f98e5da292fcd7104391afef5105c35bb2f312e29bea6f5fa419935255c", size = 13494046, upload-time = "2026-08-26T20:23:12.191Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/bc/6e/e88411a88240b94640bba06fb6d0d92b247fbeef47ee2bc71f39e58c2558/ty-0.0.55-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16c215ad9f823829409b94ee188cfaa4563f6e1384f6ce3fecb1db75f6c7cf7c", size = 12673086, upload-time = "2026-06-27T00:27:05.589Z" },
|
{ url = "https://files.pythonhosted.org/packages/2c/0d/502d2dd68173cf020e1ad2bdbab9544c86776de0b0e2ed15f8c2fe006e3d/ty-0.0.75-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac13b180dc2aade2cd243f56b01650e78bf091a2e522ad3bc947245d7837c613", size = 13938899, upload-time = "2026-08-26T20:23:14.764Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6c/7e/8f1762fb7f9245a68ba5ae338d73c59403ce57554e5d311b8bb55027b0ec/ty-0.0.55-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b510eb8f4032baf11b7aee2f1d53babc3b4ca03939b9cdcf6a9d15761d575188", size = 12242559, upload-time = "2026-06-27T00:27:07.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/20/5b/f3b12a25c07224456219fc2bd20db0ad7e40b304be0ff6aad728da0135f9/ty-0.0.75-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:752df7951a443219d7f1ff817e3723c85d428565ff449e08a7a93ba821661526", size = 13656711, upload-time = "2026-08-26T20:23:17.145Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/72/1f/143657daf2670d977dac83435f1fe03d4843efb798d8e1e75950e541aadd/ty-0.0.55-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0ddc05e7959709c3b9b83aa627128a80446865e3c1a4882638dcff6d776dc34a", size = 12021409, upload-time = "2026-06-27T00:27:09.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/51/7b/f090ad306e2b15a07b332d647138c5264b89d9758855ecce8b8a10bcb153/ty-0.0.75-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1fd399feedf7cee816563c1baec45fc1c0b3c89f1ea42364920b688004b5b7da", size = 13093499, upload-time = "2026-08-26T20:23:19.489Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/6d/30/69487c439dd1fad3a4a3d96f0a472193de297eaba6fc4b8ea687ce434ac2/ty-0.0.55-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:636e8e5078787b8c6916c94e1406719f10189a4ca6b37b813a5922ce5857a8c7", size = 12303807, upload-time = "2026-06-27T00:27:11.986Z" },
|
{ url = "https://files.pythonhosted.org/packages/f1/4b/f69b99aaaca0c7c65d5f114b186b26b21666f767b0c69eec99a2bdccc061/ty-0.0.75-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:d7625f6f56c7dc1e873579fdc9e432a0e21e302afe847ab60704d2303442a92e", size = 13520580, upload-time = "2026-08-26T20:23:21.789Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/e8/ca/cd88b6493dafc7db077f5e17c0438eb3af6e2d6d08f616dbb52a8ddfd567/ty-0.0.55-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ef7d6deaacb73fec603666b5471f1dc5a5699aa84e11a6d4d644dd07ca72121e", size = 11441263, upload-time = "2026-06-27T00:27:14.087Z" },
|
{ url = "https://files.pythonhosted.org/packages/b6/e7/692c5f905c0345a15d2255fc74066d660f030254ae8dcdaf33f5a5c2f279/ty-0.0.75-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:89e7d527e95a2534b70cae29e94c104b84082760ea05927d23bb87280969c104", size = 12524095, upload-time = "2026-08-26T20:23:24.026Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/aa/fe/66b6915671653ab739f71e4f1b0528e69da64429b7ebf3840c625b6e43f2/ty-0.0.55-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:9aeea0fe5875d3cf37faf0e44d0fdf9669335467749741b8fc0103916fb5cd32", size = 11484584, upload-time = "2026-06-27T00:27:16.311Z" },
|
{ url = "https://files.pythonhosted.org/packages/ba/9a/f42b12cf265ea95344bf554764c4791cfb273bdd628aadd7c209af7cadc3/ty-0.0.75-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:0843f134440740706e01bee5f88f4cfc10e9b018bddb9e4ef4c12dc9fc0c9aef", size = 12756591, upload-time = "2026-08-26T20:23:26.126Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4a/4f/7a9c0bbac8b899e9f6c0ec110c6612f52e4db35f6bb17ddc0ef60384fa3e/ty-0.0.55-py3-none-musllinux_1_2_i686.whl", hash = "sha256:0b699c01310dbd2705a07c97c5f4aaeedef61bd9adeea2e7c46aed32401d3576", size = 11759309, upload-time = "2026-06-27T00:27:18.471Z" },
|
{ url = "https://files.pythonhosted.org/packages/7c/5e/9b180c133cb9cce48179a7d2bf9e1802d992aa8176a918e0e05205760b42/ty-0.0.75-py3-none-musllinux_1_2_i686.whl", hash = "sha256:1bd0ec0e50ee1376875c88891efe6f549c3560fa5b2ddad79a425cd5a6218b9c", size = 12998754, upload-time = "2026-08-26T20:23:28.353Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/ca/de/b6f8b1b69aa631b5716ef3f985c3b56de0e46c2499cc00d30c402b41f714/ty-0.0.55-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:32cbeba543e46de2a983ec6d525d8b56514f7422bd1e1b57c44ccf7bfa72c38a", size = 12128755, upload-time = "2026-06-27T00:27:20.55Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/f6/3c6ef5dd550103e29905121c67fb96a374564f31a2f44c6faa1af98c2d61/ty-0.0.75-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1f9eafd561f90110d5e29f589ec3e956c4686e2f6631348d99276436f5cbe4d1", size = 13316474, upload-time = "2026-08-26T20:23:30.857Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/7d/90/a912531e51ee7e076b42972479290fa687c0f5e747b7e773f3033164acaa/ty-0.0.55-py3-none-win32.whl", hash = "sha256:52b968e24eb4f7a5c3bd251db1f99f60dd385890356d38fc619d84f1b423446a", size = 11117501, upload-time = "2026-06-27T00:27:22.714Z" },
|
{ url = "https://files.pythonhosted.org/packages/bb/52/12776337874c821076bd5368e352ccd9e67174790abe3b856f749cb3524b/ty-0.0.75-py3-none-win32.whl", hash = "sha256:05063a6fafe2154b794a7f964515d148e51acd186d72d4a3acd347ee9fa19336", size = 12316315, upload-time = "2026-08-26T20:23:33.528Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/4c/7a/99d59843bf8908a7f9f4d13fda107dbad07b7faa28ecd7860eacf363fb1c/ty-0.0.55-py3-none-win_amd64.whl", hash = "sha256:bf39cbfdc0add44d94bd3fff1f53c351418d134b6a66b87efdb7876d7b7a2224", size = 12150106, upload-time = "2026-06-27T00:27:24.881Z" },
|
{ url = "https://files.pythonhosted.org/packages/53/e6/bb51e16af5c7138c9f52f8f3d0a401a371c6798d092e3b74926f186a9814/ty-0.0.75-py3-none-win_amd64.whl", hash = "sha256:81cf1ba5f6b7536ad56747865214255d9bc8e80533a689dbb9ddeaad464b09f1", size = 12917267, upload-time = "2026-08-26T20:23:35.978Z" },
|
||||||
{ url = "https://files.pythonhosted.org/packages/b3/44/20987505cedf2a865b08482f0eabc181fd9599b062964057ec8a128a4296/ty-0.0.55-py3-none-win_arm64.whl", hash = "sha256:f7f3700a9a060e8f1af11e4fb63fafcaf272b041781f4ccdfda2b3b5c6c1e439", size = 11560157, upload-time = "2026-06-27T00:27:27.332Z" },
|
{ url = "https://files.pythonhosted.org/packages/39/73/4542f829107468b5de4231af67f29927c093bfad11f3c1e5b2c08fb1206b/ty-0.0.75-py3-none-win_arm64.whl", hash = "sha256:541c9af5b7a0ad23d15ec315a7da81150833c359f48124ed3789ff25eacd6f42", size = 12711024, upload-time = "2026-08-26T20:23:38.159Z" },
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@@ -2229,7 +2234,7 @@ name = "typing-inspection"
|
|||||||
version = "0.4.2"
|
version = "0.4.2"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "typing-extensions", marker = "python_full_version >= '3.11'" },
|
{ name = "typing-extensions" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/55/e3/70399cb7dd41c10ac53367ae42139cf4b1ca5f36bb3dc6c9d33acdb43655/typing_inspection-0.4.2.tar.gz", hash = "sha256:ba561c48a67c5958007083d386c3295464928b01faa735ab8547c5692e87f464", size = 75949, upload-time = "2025-10-01T02:14:41.687Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -2317,8 +2322,8 @@ name = "uvicorn"
|
|||||||
version = "0.44.0"
|
version = "0.44.0"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "click", marker = "python_full_version >= '3.11'" },
|
{ name = "click" },
|
||||||
{ name = "h11", marker = "python_full_version >= '3.11'" },
|
{ name = "h11" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/5e/da/6eee1ff8b6cbeed47eeb5229749168e81eb4b7b999a1a15a7176e51410c9/uvicorn-0.44.0.tar.gz", hash = "sha256:6c942071b68f07e178264b9152f1f16dfac5da85880c4ce06366a96d70d4f31e", size = 86947, upload-time = "2026-04-06T09:23:22.826Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/5e/da/6eee1ff8b6cbeed47eeb5229749168e81eb4b7b999a1a15a7176e51410c9/uvicorn-0.44.0.tar.gz", hash = "sha256:6c942071b68f07e178264b9152f1f16dfac5da85880c4ce06366a96d70d4f31e", size = 86947, upload-time = "2026-04-06T09:23:22.826Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
@@ -2422,7 +2427,7 @@ name = "watchfiles"
|
|||||||
version = "1.1.1"
|
version = "1.1.1"
|
||||||
source = { registry = "https://pypi.org/simple" }
|
source = { registry = "https://pypi.org/simple" }
|
||||||
dependencies = [
|
dependencies = [
|
||||||
{ name = "anyio", marker = "python_full_version >= '3.11'" },
|
{ name = "anyio" },
|
||||||
]
|
]
|
||||||
sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" }
|
sdist = { url = "https://files.pythonhosted.org/packages/c2/c9/8869df9b2a2d6c59d79220a4db37679e74f807c559ffe5265e08b227a210/watchfiles-1.1.1.tar.gz", hash = "sha256:a173cb5c16c4f40ab19cecf48a534c409f7ea983ab8fed0741304a1c0a31b3f2", size = 94440, upload-time = "2025-10-14T15:06:21.08Z" }
|
||||||
wheels = [
|
wheels = [
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ def _create_root_model(
|
|||||||
|
|
||||||
def schema(
|
def schema(
|
||||||
cls: type[BaseModel],
|
cls: type[BaseModel],
|
||||||
by_alias: bool = True, # noqa: FBT001,FBT002
|
by_alias: bool = True,
|
||||||
ref_template: str = DEFAULT_REF_TEMPLATE,
|
ref_template: str = DEFAULT_REF_TEMPLATE,
|
||||||
) -> dict[str, Any]:
|
) -> dict[str, Any]:
|
||||||
# Complains about schema not being defined in superclass
|
# Complains about schema not being defined in superclass
|
||||||
@@ -80,7 +80,7 @@ def _create_root_model(
|
|||||||
|
|
||||||
def model_json_schema(
|
def model_json_schema(
|
||||||
cls: type[BaseModel],
|
cls: type[BaseModel],
|
||||||
by_alias: bool = True, # noqa: FBT001,FBT002
|
by_alias: bool = True,
|
||||||
ref_template: str = DEFAULT_REF_TEMPLATE,
|
ref_template: str = DEFAULT_REF_TEMPLATE,
|
||||||
schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema,
|
schema_generator: type[GenerateJsonSchema] = GenerateJsonSchema,
|
||||||
mode: JsonSchemaMode = "validation",
|
mode: JsonSchemaMode = "validation",
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
import enum
|
import enum
|
||||||
import inspect
|
import inspect
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from collections.abc import (
|
from collections.abc import (
|
||||||
@@ -63,6 +64,26 @@ try:
|
|||||||
except ImportError:
|
except ImportError:
|
||||||
_StreamingCallbackHandler = None # type: ignore
|
_StreamingCallbackHandler = None # type: ignore
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
def _trace_payload(value: Any, transform: Callable[[Any], Any] | None) -> Any:
|
||||||
|
"""Return the payload to record on a run for `value`.
|
||||||
|
|
||||||
|
When `transform` is unset this is a passthrough, so unspecified nodes record exactly
|
||||||
|
as before. When set it always runs (regardless of tracing), but never affects
|
||||||
|
execution: if it raises, the untransformed value is recorded instead.
|
||||||
|
"""
|
||||||
|
if transform is None:
|
||||||
|
return value
|
||||||
|
try:
|
||||||
|
return transform(value)
|
||||||
|
except Exception:
|
||||||
|
logger.exception(
|
||||||
|
"trace input/output processor raised; recording untransformed payload"
|
||||||
|
)
|
||||||
|
return value
|
||||||
|
|
||||||
|
|
||||||
def _set_config_context(
|
def _set_config_context(
|
||||||
config: RunnableConfig, run: Any = None
|
config: RunnableConfig, run: Any = None
|
||||||
@@ -572,6 +593,7 @@ class RunnableSeq(Runnable):
|
|||||||
*steps: RunnableLike,
|
*steps: RunnableLike,
|
||||||
name: str | None = None,
|
name: str | None = None,
|
||||||
trace_inputs: Callable[[Any], Any] | None = None,
|
trace_inputs: Callable[[Any], Any] | None = None,
|
||||||
|
trace_outputs: Callable[[Any], Any] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
"""Create a new RunnableSeq.
|
"""Create a new RunnableSeq.
|
||||||
|
|
||||||
@@ -597,6 +619,7 @@ class RunnableSeq(Runnable):
|
|||||||
self.steps = steps_flat
|
self.steps = steps_flat
|
||||||
self.name = name
|
self.name = name
|
||||||
self.trace_inputs = trace_inputs
|
self.trace_inputs = trace_inputs
|
||||||
|
self.trace_outputs = trace_outputs
|
||||||
|
|
||||||
def __or__(
|
def __or__(
|
||||||
self,
|
self,
|
||||||
@@ -658,7 +681,7 @@ class RunnableSeq(Runnable):
|
|||||||
# start the root run
|
# start the root run
|
||||||
run_manager = callback_manager.on_chain_start(
|
run_manager = callback_manager.on_chain_start(
|
||||||
None,
|
None,
|
||||||
self.trace_inputs(input) if self.trace_inputs is not None else input,
|
_trace_payload(input, self.trace_inputs),
|
||||||
name=config.get("run_name") or self.get_name(),
|
name=config.get("run_name") or self.get_name(),
|
||||||
run_id=config.pop("run_id", None),
|
run_id=config.pop("run_id", None),
|
||||||
)
|
)
|
||||||
@@ -689,7 +712,7 @@ class RunnableSeq(Runnable):
|
|||||||
run_manager.on_chain_error(e)
|
run_manager.on_chain_error(e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
run_manager.on_chain_end(input)
|
run_manager.on_chain_end(_trace_payload(input, self.trace_outputs))
|
||||||
return input
|
return input
|
||||||
|
|
||||||
async def ainvoke(
|
async def ainvoke(
|
||||||
@@ -705,7 +728,7 @@ class RunnableSeq(Runnable):
|
|||||||
# start the root run
|
# start the root run
|
||||||
run_manager = await callback_manager.on_chain_start(
|
run_manager = await callback_manager.on_chain_start(
|
||||||
None,
|
None,
|
||||||
self.trace_inputs(input) if self.trace_inputs is not None else input,
|
_trace_payload(input, self.trace_inputs),
|
||||||
name=config.get("run_name") or self.get_name(),
|
name=config.get("run_name") or self.get_name(),
|
||||||
run_id=config.pop("run_id", None),
|
run_id=config.pop("run_id", None),
|
||||||
)
|
)
|
||||||
@@ -742,7 +765,7 @@ class RunnableSeq(Runnable):
|
|||||||
await run_manager.on_chain_error(e)
|
await run_manager.on_chain_error(e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
await run_manager.on_chain_end(input)
|
await run_manager.on_chain_end(_trace_payload(input, self.trace_outputs))
|
||||||
return input
|
return input
|
||||||
|
|
||||||
def stream(
|
def stream(
|
||||||
@@ -758,7 +781,7 @@ class RunnableSeq(Runnable):
|
|||||||
# start the root run
|
# start the root run
|
||||||
run_manager = callback_manager.on_chain_start(
|
run_manager = callback_manager.on_chain_start(
|
||||||
None,
|
None,
|
||||||
self.trace_inputs(input) if self.trace_inputs is not None else input,
|
_trace_payload(input, self.trace_inputs),
|
||||||
name=config.get("run_name") or self.get_name(),
|
name=config.get("run_name") or self.get_name(),
|
||||||
run_id=config.pop("run_id", None),
|
run_id=config.pop("run_id", None),
|
||||||
)
|
)
|
||||||
@@ -803,7 +826,7 @@ class RunnableSeq(Runnable):
|
|||||||
run_manager.on_chain_error(e)
|
run_manager.on_chain_error(e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
run_manager.on_chain_end(output)
|
run_manager.on_chain_end(_trace_payload(output, self.trace_outputs))
|
||||||
|
|
||||||
async def astream(
|
async def astream(
|
||||||
self,
|
self,
|
||||||
@@ -818,7 +841,7 @@ class RunnableSeq(Runnable):
|
|||||||
# start the root run
|
# start the root run
|
||||||
run_manager = await callback_manager.on_chain_start(
|
run_manager = await callback_manager.on_chain_start(
|
||||||
None,
|
None,
|
||||||
self.trace_inputs(input) if self.trace_inputs is not None else input,
|
_trace_payload(input, self.trace_inputs),
|
||||||
name=config.get("run_name") or self.get_name(),
|
name=config.get("run_name") or self.get_name(),
|
||||||
run_id=config.pop("run_id", None),
|
run_id=config.pop("run_id", None),
|
||||||
)
|
)
|
||||||
@@ -873,7 +896,9 @@ class RunnableSeq(Runnable):
|
|||||||
await run_manager.on_chain_error(e)
|
await run_manager.on_chain_error(e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
await run_manager.on_chain_end(output)
|
await run_manager.on_chain_end(
|
||||||
|
_trace_payload(output, self.trace_outputs)
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
async with AsyncExitStack() as stack:
|
async with AsyncExitStack() as stack:
|
||||||
@@ -903,7 +928,9 @@ class RunnableSeq(Runnable):
|
|||||||
await run_manager.on_chain_error(e)
|
await run_manager.on_chain_error(e)
|
||||||
raise
|
raise
|
||||||
else:
|
else:
|
||||||
await run_manager.on_chain_end(output)
|
await run_manager.on_chain_end(
|
||||||
|
_trace_payload(output, self.trace_outputs)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def _consume_iter(it: Iterator[Any]) -> Any:
|
def _consume_iter(it: Iterator[Any]) -> Any:
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ from pydantic import BaseModel
|
|||||||
from typing_extensions import NotRequired, Required, is_typeddict
|
from typing_extensions import NotRequired, Required, is_typeddict
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from langgraph.checkpoint.serde._msgpack import ( # noqa: F401
|
from langgraph.checkpoint.serde._msgpack import (
|
||||||
STRICT_MSGPACK_ENABLED,
|
STRICT_MSGPACK_ENABLED,
|
||||||
)
|
)
|
||||||
except ImportError:
|
except ImportError:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ from typing import Any, Literal
|
|||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
# EmptyChannelError is re-exported from langgraph.channels.base
|
# EmptyChannelError is re-exported from langgraph.channels.base
|
||||||
from langgraph.checkpoint.base import EmptyChannelError # noqa: F401
|
from langgraph.checkpoint.base import EmptyChannelError
|
||||||
from typing_extensions import deprecated
|
from typing_extensions import deprecated
|
||||||
|
|
||||||
from langgraph.types import Command, Interrupt
|
from langgraph.types import Command, Interrupt
|
||||||
|
|||||||
@@ -9,7 +9,13 @@ from langgraph.store.base import BaseStore
|
|||||||
|
|
||||||
from langgraph._internal._typing import EMPTY_SEQ
|
from langgraph._internal._typing import EMPTY_SEQ
|
||||||
from langgraph.runtime import Runtime
|
from langgraph.runtime import Runtime
|
||||||
from langgraph.types import CachePolicy, RetryPolicy, StreamWriter, TimeoutPolicy
|
from langgraph.types import (
|
||||||
|
CachePolicy,
|
||||||
|
RetryPolicy,
|
||||||
|
StreamWriter,
|
||||||
|
TimeoutPolicy,
|
||||||
|
TracePolicy,
|
||||||
|
)
|
||||||
from langgraph.typing import ContextT, NodeInputT, NodeInputT_contra
|
from langgraph.typing import ContextT, NodeInputT, NodeInputT_contra
|
||||||
|
|
||||||
|
|
||||||
@@ -93,3 +99,5 @@ class StateNodeSpec(Generic[NodeInputT, ContextT]):
|
|||||||
ends: tuple[str, ...] | dict[str, str] | None = EMPTY_SEQ
|
ends: tuple[str, ...] | dict[str, str] | None = EMPTY_SEQ
|
||||||
defer: bool = False
|
defer: bool = False
|
||||||
timeout: TimeoutPolicy | None = None
|
timeout: TimeoutPolicy | None = None
|
||||||
|
trace_policy: TracePolicy | None = None
|
||||||
|
"""Optional policy controlling what this node records on its trace run."""
|
||||||
|
|||||||
@@ -85,6 +85,7 @@ from langgraph.types import (
|
|||||||
RetryPolicy,
|
RetryPolicy,
|
||||||
Send,
|
Send,
|
||||||
TimeoutPolicy,
|
TimeoutPolicy,
|
||||||
|
TracePolicy,
|
||||||
ensure_valid_checkpointer,
|
ensure_valid_checkpointer,
|
||||||
)
|
)
|
||||||
from langgraph.typing import ContextT, InputT, NodeInputT, OutputT, StateT
|
from langgraph.typing import ContextT, InputT, NodeInputT, OutputT, StateT
|
||||||
@@ -384,6 +385,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
error_handler: StateNode[Any, ContextT] | None = None,
|
error_handler: StateNode[Any, ContextT] | None = None,
|
||||||
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
||||||
timeout: float | timedelta | TimeoutPolicy | None = None,
|
timeout: float | timedelta | TimeoutPolicy | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
**kwargs: Unpack[DeprecatedKwargs],
|
**kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Add a new node to the `StateGraph`, input schema is inferred as the state schema.
|
"""Add a new node to the `StateGraph`, input schema is inferred as the state schema.
|
||||||
@@ -453,6 +455,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
error_handler: StateNode[Any, ContextT] | None = None,
|
error_handler: StateNode[Any, ContextT] | None = None,
|
||||||
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
||||||
timeout: float | timedelta | TimeoutPolicy | None = None,
|
timeout: float | timedelta | TimeoutPolicy | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
**kwargs: Unpack[DeprecatedKwargs],
|
**kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Add a new node to the `StateGraph` where input schema is specified.
|
"""Add a new node to the `StateGraph` where input schema is specified.
|
||||||
@@ -527,6 +530,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
error_handler: StateNode[Any, ContextT] | None = None,
|
error_handler: StateNode[Any, ContextT] | None = None,
|
||||||
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
||||||
timeout: float | timedelta | TimeoutPolicy | None = None,
|
timeout: float | timedelta | TimeoutPolicy | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
**kwargs: Unpack[DeprecatedKwargs],
|
**kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Add a new node to the `StateGraph`, input schema is inferred as the state schema.
|
"""Add a new node to the `StateGraph`, input schema is inferred as the state schema.
|
||||||
@@ -596,6 +600,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
error_handler: StateNode[Any, ContextT] | None = None,
|
error_handler: StateNode[Any, ContextT] | None = None,
|
||||||
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
||||||
timeout: float | timedelta | TimeoutPolicy | None = None,
|
timeout: float | timedelta | TimeoutPolicy | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
**kwargs: Unpack[DeprecatedKwargs],
|
**kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Add a new node to the `StateGraph`, input schema is specified.
|
"""Add a new node to the `StateGraph`, input schema is specified.
|
||||||
@@ -672,6 +677,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
error_handler: StateNode[Any, ContextT] | None = None,
|
error_handler: StateNode[Any, ContextT] | None = None,
|
||||||
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
destinations: dict[str, str] | tuple[str, ...] | None = None,
|
||||||
timeout: float | timedelta | TimeoutPolicy | None = None,
|
timeout: float | timedelta | TimeoutPolicy | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
**kwargs: Unpack[DeprecatedKwargs],
|
**kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> Self:
|
) -> Self:
|
||||||
"""Add a new node to the `StateGraph`.
|
"""Add a new node to the `StateGraph`.
|
||||||
@@ -691,6 +697,10 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
If a sequence is provided, the first matching policy will be applied.
|
If a sequence is provided, the first matching policy will be applied.
|
||||||
cache_policy: The cache policy for the node.
|
cache_policy: The cache policy for the node.
|
||||||
error_handler: Optional node-level error handler callable for this node.
|
error_handler: Optional node-level error handler callable for this node.
|
||||||
|
trace_policy: Optional policy controlling how this node's run is traced. Its
|
||||||
|
`process_inputs` callable transforms the node's input before it is
|
||||||
|
recorded (e.g. to omit or summarize large message history) without
|
||||||
|
changing the value passed to the node. Does not affect execution.
|
||||||
destinations: Destinations that indicate where a node can route to.
|
destinations: Destinations that indicate where a node can route to.
|
||||||
|
|
||||||
Useful for edgeless graphs with nodes that return `Command` objects.
|
Useful for edgeless graphs with nodes that return `Command` objects.
|
||||||
@@ -880,6 +890,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
ends=ends,
|
ends=ends,
|
||||||
defer=defer,
|
defer=defer,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
trace_policy=trace_policy,
|
||||||
)
|
)
|
||||||
elif inferred_input_schema is not None:
|
elif inferred_input_schema is not None:
|
||||||
self.nodes[node] = StateNodeSpec(
|
self.nodes[node] = StateNodeSpec(
|
||||||
@@ -892,6 +903,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
ends=ends,
|
ends=ends,
|
||||||
defer=defer,
|
defer=defer,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
trace_policy=trace_policy,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
self.nodes[node] = StateNodeSpec[StateT, ContextT](
|
self.nodes[node] = StateNodeSpec[StateT, ContextT](
|
||||||
@@ -904,6 +916,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
ends=ends,
|
ends=ends,
|
||||||
defer=defer,
|
defer=defer,
|
||||||
timeout=timeout,
|
timeout=timeout,
|
||||||
|
trace_policy=trace_policy,
|
||||||
)
|
)
|
||||||
|
|
||||||
input_schema = input_schema or inferred_input_schema
|
input_schema = input_schema or inferred_input_schema
|
||||||
@@ -995,7 +1008,7 @@ class StateGraph(Generic[StateT, ContextT, InputT, OutputT]):
|
|||||||
Without type hints on the `path` function's return value (e.g., `-> Literal["foo", "__end__"]:`)
|
Without type hints on the `path` function's return value (e.g., `-> Literal["foo", "__end__"]:`)
|
||||||
or a path_map, the graph visualization assumes the edge could transition to any node in the graph.
|
or a path_map, the graph visualization assumes the edge could transition to any node in the graph.
|
||||||
|
|
||||||
""" # noqa: E501
|
"""
|
||||||
if self.compiled:
|
if self.compiled:
|
||||||
logger.warning(
|
logger.warning(
|
||||||
"Adding an edge to a graph that has already been compiled. This will "
|
"Adding an edge to a graph that has already been compiled. This will "
|
||||||
@@ -1530,6 +1543,7 @@ class CompiledStateGraph(
|
|||||||
error_handler_node=node.error_handler_node,
|
error_handler_node=node.error_handler_node,
|
||||||
bound=node.runnable, # type: ignore[arg-type]
|
bound=node.runnable, # type: ignore[arg-type]
|
||||||
timeout=node.timeout,
|
timeout=node.timeout,
|
||||||
|
trace_policy=node.trace_policy,
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
raise RuntimeError
|
raise RuntimeError
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ from langgraph._internal._timeout import coerce_timeout_policy
|
|||||||
from langgraph.pregel._utils import find_subgraph_pregel
|
from langgraph.pregel._utils import find_subgraph_pregel
|
||||||
from langgraph.pregel._write import ChannelWrite
|
from langgraph.pregel._write import ChannelWrite
|
||||||
from langgraph.pregel.protocol import PregelProtocol
|
from langgraph.pregel.protocol import PregelProtocol
|
||||||
from langgraph.types import CachePolicy, RetryPolicy, TimeoutPolicy
|
from langgraph.types import CachePolicy, RetryPolicy, TimeoutPolicy, TracePolicy
|
||||||
|
|
||||||
READ_TYPE = Callable[[str | Sequence[str], bool], Any | dict[str, Any]]
|
READ_TYPE = Callable[[str | Sequence[str], bool], Any | dict[str, Any]]
|
||||||
INPUT_CACHE_KEY_TYPE = tuple[Callable[..., Any], tuple[str, ...]]
|
INPUT_CACHE_KEY_TYPE = tuple[Callable[..., Any], tuple[str, ...]]
|
||||||
@@ -138,6 +138,9 @@ class PregelNode:
|
|||||||
metadata: Mapping[str, Any] | None
|
metadata: Mapping[str, Any] | None
|
||||||
"""Metadata to attach to the node for tracing."""
|
"""Metadata to attach to the node for tracing."""
|
||||||
|
|
||||||
|
trace_policy: TracePolicy | None
|
||||||
|
"""Optional policy controlling what this node records on its trace run."""
|
||||||
|
|
||||||
is_error_handler: bool
|
is_error_handler: bool
|
||||||
"""Whether this node is registered as an error handler node."""
|
"""Whether this node is registered as an error handler node."""
|
||||||
|
|
||||||
@@ -156,6 +159,7 @@ class PregelNode:
|
|||||||
writers: list[Runnable] | None = None,
|
writers: list[Runnable] | None = None,
|
||||||
tags: list[str] | None = None,
|
tags: list[str] | None = None,
|
||||||
metadata: Mapping[str, Any] | None = None,
|
metadata: Mapping[str, Any] | None = None,
|
||||||
|
trace_policy: TracePolicy | None = None,
|
||||||
bound: Runnable[Any, Any] | None = None,
|
bound: Runnable[Any, Any] | None = None,
|
||||||
retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
|
retry_policy: RetryPolicy | Sequence[RetryPolicy] | None = None,
|
||||||
cache_policy: CachePolicy | None = None,
|
cache_policy: CachePolicy | None = None,
|
||||||
@@ -177,6 +181,7 @@ class PregelNode:
|
|||||||
self.timeout = coerce_timeout_policy(timeout)
|
self.timeout = coerce_timeout_policy(timeout)
|
||||||
self.tags = tags
|
self.tags = tags
|
||||||
self.metadata = metadata
|
self.metadata = metadata
|
||||||
|
self.trace_policy = trace_policy
|
||||||
self.is_error_handler = is_error_handler
|
self.is_error_handler = is_error_handler
|
||||||
self.error_handler_node = error_handler_node
|
self.error_handler_node = error_handler_node
|
||||||
if subgraphs is not None:
|
if subgraphs is not None:
|
||||||
@@ -222,14 +227,23 @@ class PregelNode:
|
|||||||
def node(self) -> Runnable[Any, Any] | None:
|
def node(self) -> Runnable[Any, Any] | None:
|
||||||
"""Get a runnable that combines `bound` and `writers`."""
|
"""Get a runnable that combines `bound` and `writers`."""
|
||||||
writers = self.flat_writers
|
writers = self.flat_writers
|
||||||
|
trace_inputs = self.trace_policy.process_inputs if self.trace_policy else None
|
||||||
|
trace_outputs = self.trace_policy.process_outputs if self.trace_policy else None
|
||||||
if self.bound is DEFAULT_BOUND and not writers:
|
if self.bound is DEFAULT_BOUND and not writers:
|
||||||
return None
|
return None
|
||||||
elif self.bound is DEFAULT_BOUND and len(writers) == 1:
|
elif self.bound is DEFAULT_BOUND and len(writers) == 1:
|
||||||
return writers[0]
|
return writers[0]
|
||||||
elif self.bound is DEFAULT_BOUND:
|
elif self.bound is DEFAULT_BOUND:
|
||||||
return RunnableSeq(*writers)
|
return RunnableSeq(
|
||||||
|
*writers, trace_inputs=trace_inputs, trace_outputs=trace_outputs
|
||||||
|
)
|
||||||
elif writers:
|
elif writers:
|
||||||
return RunnableSeq(self.bound, *writers)
|
return RunnableSeq(
|
||||||
|
self.bound,
|
||||||
|
*writers,
|
||||||
|
trace_inputs=trace_inputs,
|
||||||
|
trace_outputs=trace_outputs,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
return self.bound
|
return self.bound
|
||||||
|
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
import ast
|
import dis
|
||||||
import inspect
|
|
||||||
import re
|
import re
|
||||||
import textwrap
|
|
||||||
from collections.abc import Callable, Sequence
|
from collections.abc import Callable, Sequence
|
||||||
from functools import partial
|
from functools import partial
|
||||||
|
from types import CodeType, FunctionType
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from langchain_core.runnables import (
|
from langchain_core.runnables import (
|
||||||
@@ -17,7 +16,6 @@ from langchain_core.runnables import (
|
|||||||
from langchain_core.runnables.base import RunnableBindingBase
|
from langchain_core.runnables.base import RunnableBindingBase
|
||||||
from langchain_core.runnables.config import run_in_executor
|
from langchain_core.runnables.config import run_in_executor
|
||||||
from langgraph.checkpoint.base import ChannelVersions
|
from langgraph.checkpoint.base import ChannelVersions
|
||||||
from typing_extensions import override
|
|
||||||
|
|
||||||
from langgraph._internal._runnable import RunnableCallable, RunnableSeq
|
from langgraph._internal._runnable import RunnableCallable, RunnableSeq
|
||||||
from langgraph._internal._timeout import sync_timeout_unsupported
|
from langgraph._internal._timeout import sync_timeout_unsupported
|
||||||
@@ -137,153 +135,85 @@ def validate_timeout_supported(runnable: Runnable, *, name: str) -> None:
|
|||||||
raise sync_timeout_unsupported(name)
|
raise sync_timeout_unsupported(name)
|
||||||
|
|
||||||
|
|
||||||
|
# Values treated as dead ends when deciding whether to walk a function's
|
||||||
|
# bytecode. A container can hold a graph, but `find_subgraph_pregel` does not
|
||||||
|
# look inside one, so skipping it costs nothing while that holds. Matched by
|
||||||
|
# exact type, since a subclass of a builtin can carry attributes.
|
||||||
|
_LEAF_TYPES = frozenset(
|
||||||
|
{
|
||||||
|
int,
|
||||||
|
float,
|
||||||
|
complex,
|
||||||
|
bool,
|
||||||
|
str,
|
||||||
|
bytes,
|
||||||
|
bytearray,
|
||||||
|
list,
|
||||||
|
tuple,
|
||||||
|
dict,
|
||||||
|
set,
|
||||||
|
frozenset,
|
||||||
|
type(None),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_function_nonlocals(func: Callable) -> list[Any]:
|
def get_function_nonlocals(func: Callable) -> list[Any]:
|
||||||
"""Get the nonlocal variables accessed by a function.
|
"""Get the values a function reaches from outside its own scope.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
func: The function to check.
|
func: The function to check.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
List[Any]: The nonlocal variables accessed by the function.
|
Every captured cell value, the globals the function names, and each
|
||||||
|
value along an attribute path it loads. Over-approximates: a value can
|
||||||
|
come back without the function reaching it at runtime.
|
||||||
"""
|
"""
|
||||||
try:
|
func = getattr(func, "__func__", func) # bound method -> function
|
||||||
code = inspect.getsource(func)
|
wrapped = getattr(func, "__wrapped__", None)
|
||||||
tree = ast.parse(textwrap.dedent(code))
|
if callable(wrapped):
|
||||||
visitor = FunctionNonLocals()
|
func = getattr(wrapped, "__func__", wrapped)
|
||||||
visitor.visit(tree)
|
if not isinstance(func, FunctionType):
|
||||||
values: list[Any] = []
|
|
||||||
closure = (
|
|
||||||
inspect.getclosurevars(func.__wrapped__)
|
|
||||||
if hasattr(func, "__wrapped__") and callable(func.__wrapped__)
|
|
||||||
else inspect.getclosurevars(func)
|
|
||||||
)
|
|
||||||
candidates = {**closure.globals, **closure.nonlocals}
|
|
||||||
for k, v in candidates.items():
|
|
||||||
if k in visitor.nonlocals:
|
|
||||||
values.append(v)
|
|
||||||
for kk in visitor.nonlocals:
|
|
||||||
if "." in kk and kk.startswith(k):
|
|
||||||
vv = v
|
|
||||||
for part in kk.split(".")[1:]:
|
|
||||||
if vv is None:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
vv = getattr(vv, part)
|
|
||||||
except AttributeError:
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
values.append(vv)
|
|
||||||
except (SyntaxError, TypeError, OSError, SystemError):
|
|
||||||
return []
|
return []
|
||||||
|
code = func.__code__
|
||||||
|
|
||||||
|
cells: dict[str, Any] = {}
|
||||||
|
for name, cell in zip(code.co_freevars, func.__closure__ or ()):
|
||||||
|
try:
|
||||||
|
cells[name] = cell.cell_contents
|
||||||
|
except ValueError:
|
||||||
|
continue # empty cell: a recursive def not yet bound
|
||||||
|
|
||||||
|
# Every captured value counts, referenced or not: over-declaring costs an
|
||||||
|
# introspection entry, under-declaring drops the subgraph's checkpoints and
|
||||||
|
# stream events. Checking each cell against the bytecode would cost more and
|
||||||
|
# only trade the cheap error for the expensive one.
|
||||||
|
values: list[Any] = list(cells.values())
|
||||||
|
global_ns = func.__globals__
|
||||||
|
globals_ = {name: global_ns[name] for name in code.co_names if name in global_ns}
|
||||||
|
if all(type(v) in _LEAF_TYPES for v in (*cells.values(), *globals_.values())):
|
||||||
return values
|
return values
|
||||||
|
|
||||||
|
# Nested code objects hold the references made by inner defs, lambdas and
|
||||||
class FunctionNonLocals(ast.NodeVisitor):
|
# comprehensions, which resolve against the namespaces gathered above.
|
||||||
"""Get the nonlocal variables accessed of a function."""
|
codes = [code]
|
||||||
|
for c in codes:
|
||||||
def __init__(self) -> None:
|
codes.extend(k for k in c.co_consts if isinstance(k, CodeType))
|
||||||
self.nonlocals: set[str] = set()
|
value: Any = None
|
||||||
|
for instruction in dis.get_instructions(c):
|
||||||
@override
|
opname = instruction.opname
|
||||||
def visit_FunctionDef(self, node: ast.FunctionDef) -> Any:
|
if opname == "LOAD_GLOBAL":
|
||||||
"""Visit a function definition.
|
value = globals_.get(instruction.argval)
|
||||||
|
elif opname == "LOAD_DEREF":
|
||||||
Args:
|
value = cells.get(instruction.argval)
|
||||||
node: The node to visit.
|
elif opname in ("LOAD_ATTR", "LOAD_METHOD"):
|
||||||
|
value = getattr(value, instruction.argval, None)
|
||||||
Returns:
|
|
||||||
Any: The result of the visit.
|
|
||||||
"""
|
|
||||||
visitor = NonLocals()
|
|
||||||
visitor.visit(node)
|
|
||||||
self.nonlocals.update(visitor.loads - visitor.stores)
|
|
||||||
|
|
||||||
@override
|
|
||||||
def visit_AsyncFunctionDef(self, node: ast.AsyncFunctionDef) -> Any:
|
|
||||||
"""Visit an async function definition.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
node: The node to visit.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: The result of the visit.
|
|
||||||
"""
|
|
||||||
visitor = NonLocals()
|
|
||||||
visitor.visit(node)
|
|
||||||
self.nonlocals.update(visitor.loads - visitor.stores)
|
|
||||||
|
|
||||||
@override
|
|
||||||
def visit_Lambda(self, node: ast.Lambda) -> Any:
|
|
||||||
"""Visit a lambda function.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
node: The node to visit.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: The result of the visit.
|
|
||||||
"""
|
|
||||||
visitor = NonLocals()
|
|
||||||
visitor.visit(node)
|
|
||||||
self.nonlocals.update(visitor.loads - visitor.stores)
|
|
||||||
|
|
||||||
|
|
||||||
class NonLocals(ast.NodeVisitor):
|
|
||||||
"""Get nonlocal variables accessed."""
|
|
||||||
|
|
||||||
def __init__(self) -> None:
|
|
||||||
self.loads: set[str] = set()
|
|
||||||
self.stores: set[str] = set()
|
|
||||||
|
|
||||||
@override
|
|
||||||
def visit_Name(self, node: ast.Name) -> Any:
|
|
||||||
"""Visit a name node.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
node: The node to visit.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: The result of the visit.
|
|
||||||
"""
|
|
||||||
if isinstance(node.ctx, ast.Load):
|
|
||||||
self.loads.add(node.id)
|
|
||||||
elif isinstance(node.ctx, ast.Store):
|
|
||||||
self.stores.add(node.id)
|
|
||||||
|
|
||||||
@override
|
|
||||||
def visit_Attribute(self, node: ast.Attribute) -> Any:
|
|
||||||
"""Visit an attribute node.
|
|
||||||
|
|
||||||
Args:
|
|
||||||
node: The node to visit.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
Any: The result of the visit.
|
|
||||||
"""
|
|
||||||
if isinstance(node.ctx, ast.Load):
|
|
||||||
parent = node.value
|
|
||||||
attr_expr = node.attr
|
|
||||||
while isinstance(parent, ast.Attribute):
|
|
||||||
attr_expr = parent.attr + "." + attr_expr
|
|
||||||
parent = parent.value
|
|
||||||
if isinstance(parent, ast.Name):
|
|
||||||
self.loads.add(parent.id + "." + attr_expr)
|
|
||||||
self.loads.discard(parent.id)
|
|
||||||
elif isinstance(parent, ast.Call):
|
|
||||||
if isinstance(parent.func, ast.Name):
|
|
||||||
self.loads.add(parent.func.id)
|
|
||||||
else:
|
else:
|
||||||
parent = parent.func
|
value = None # anything else ends the chain: `a, b.c` is not `a.c`
|
||||||
attr_expr = ""
|
continue
|
||||||
while isinstance(parent, ast.Attribute):
|
if value is not None:
|
||||||
if attr_expr:
|
values.append(value)
|
||||||
attr_expr = parent.attr + "." + attr_expr
|
return values
|
||||||
else:
|
|
||||||
attr_expr = parent.attr
|
|
||||||
parent = parent.value
|
|
||||||
if isinstance(parent, ast.Name):
|
|
||||||
self.loads.add(parent.id + "." + attr_expr)
|
|
||||||
|
|
||||||
|
|
||||||
def is_xxh3_128_hexdigest(value: str) -> bool:
|
def is_xxh3_128_hexdigest(value: str) -> bool:
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ from __future__ import annotations
|
|||||||
|
|
||||||
from abc import abstractmethod
|
from abc import abstractmethod
|
||||||
from collections.abc import AsyncIterator, Callable, Iterator, Sequence
|
from collections.abc import AsyncIterator, Callable, Iterator, Sequence
|
||||||
from typing import Any, Generic, Literal, cast, overload
|
from typing import Any, Generic, Literal, overload
|
||||||
|
|
||||||
from langchain_core.runnables import Runnable, RunnableConfig
|
from langchain_core.runnables import Runnable, RunnableConfig
|
||||||
from langchain_core.runnables.graph import Graph as DrawableGraph
|
from langchain_core.runnables.graph import Graph as DrawableGraph
|
||||||
@@ -277,12 +277,12 @@ class StreamProtocol:
|
|||||||
|
|
||||||
modes: set[StreamMode]
|
modes: set[StreamMode]
|
||||||
|
|
||||||
__call__: Callable[[Self, StreamChunk], None]
|
__call__: Callable[[StreamChunk], None]
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
__call__: Callable[[StreamChunk], None],
|
__call__: Callable[[StreamChunk], None],
|
||||||
modes: set[StreamMode],
|
modes: set[StreamMode],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.__call__ = cast(Callable[[Self, StreamChunk], None], __call__)
|
self.__call__ = __call__
|
||||||
self.modes = modes
|
self.modes = modes
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ from __future__ import annotations
|
|||||||
import asyncio
|
import asyncio
|
||||||
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Mapping
|
from collections.abc import AsyncIterator, Awaitable, Callable, Iterator, Mapping
|
||||||
from types import MappingProxyType, TracebackType
|
from types import MappingProxyType, TracebackType
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any, NoReturn
|
||||||
|
|
||||||
from langchain_core._api import beta
|
from langchain_core._api import beta
|
||||||
|
|
||||||
@@ -33,6 +33,26 @@ async def _adrive_until_done(pump: Callable[[], Awaitable[bool]]) -> None:
|
|||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def _raise_missing_projection(run: object, name: str) -> NoReturn:
|
||||||
|
"""Raise after normal attribute lookup fails for a projection.
|
||||||
|
|
||||||
|
Registered native projections are installed directly on the run instance
|
||||||
|
during `__init__`, so `__getattr__` is never called for them. At this point
|
||||||
|
the requested name is necessarily missing; the mux is inspected only to
|
||||||
|
include the valid registered projection names in the error message.
|
||||||
|
|
||||||
|
Read `_mux` directly from `__dict__` because it may not exist yet on a
|
||||||
|
partially initialized instance. Accessing `run._mux` in that case would
|
||||||
|
invoke `__getattr__` again and recurse indefinitely.
|
||||||
|
"""
|
||||||
|
mux = run.__dict__.get("_mux")
|
||||||
|
registered = sorted(mux.native_keys) if mux is not None else []
|
||||||
|
raise AttributeError(
|
||||||
|
f"{type(run).__name__!r} object has no attribute {name!r} "
|
||||||
|
f"(registered projections: {', '.join(registered) or 'none'})"
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@beta(message="The v3 streaming protocol on Pregel is experimental.")
|
@beta(message="The v3 streaming protocol on Pregel is experimental.")
|
||||||
class GraphRunStream:
|
class GraphRunStream:
|
||||||
"""Sync run stream with caller-driven pumping.
|
"""Sync run stream with caller-driven pumping.
|
||||||
@@ -54,15 +74,32 @@ class GraphRunStream:
|
|||||||
experimental and may change.
|
experimental and may change.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Native projections always registered by `stream_events(version="v3")`.
|
# Native projections, attached dynamically by the `setattr` loop in
|
||||||
# Attached dynamically by the `setattr` loop in `__init__`; declared here
|
# `__init__` and declared here so type checkers see them.
|
||||||
# so type checkers see them. Opt-in native projections (`updates`,
|
#
|
||||||
# `custom`, `checkpoints`, `debug`, `tasks`) are only present when their
|
# Always registered by `stream_events(version="v3")`:
|
||||||
# transformer is registered, so they are reached via `extensions[...]`.
|
|
||||||
values: StreamChannel[dict[str, Any]]
|
values: StreamChannel[dict[str, Any]]
|
||||||
messages: StreamChannel[ChatModelStream]
|
messages: StreamChannel[ChatModelStream]
|
||||||
lifecycle: StreamChannel[LifecyclePayload]
|
lifecycle: StreamChannel[LifecyclePayload]
|
||||||
subgraphs: StreamChannel[SubgraphRunStream]
|
subgraphs: StreamChannel[SubgraphRunStream]
|
||||||
|
# Registered on demand via `compile(transformers=...)` or
|
||||||
|
# `stream_events(transformers=...)`; reading one whose transformer was not
|
||||||
|
# registered raises AttributeError. Projections contributed by transformers
|
||||||
|
# outside this package are covered by `__getattr__` instead.
|
||||||
|
updates: StreamChannel[dict[str, Any]]
|
||||||
|
custom: StreamChannel[Any]
|
||||||
|
checkpoints: StreamChannel[dict[str, Any]]
|
||||||
|
debug: StreamChannel[dict[str, Any]]
|
||||||
|
tasks: StreamChannel[dict[str, Any]]
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> StreamChannel[Any]:
|
||||||
|
"""Type the projections of transformers declared outside this package.
|
||||||
|
|
||||||
|
Projection names come from a registry, so no annotation here can name
|
||||||
|
them all. The cost is that a misspelling type-checks too, and fails at
|
||||||
|
runtime instead.
|
||||||
|
"""
|
||||||
|
_raise_missing_projection(self, name)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
@@ -345,15 +382,24 @@ class AsyncGraphRunStream:
|
|||||||
experimental and may change.
|
experimental and may change.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# Native projections always registered by `astream_events(version="v3")`.
|
# Native projections, attached dynamically by the `setattr` loop in
|
||||||
# Attached dynamically by the `setattr` loop in `__init__`; declared here
|
# `__init__` and declared here so type checkers see them.
|
||||||
# so type checkers see them. Opt-in native projections (`updates`,
|
#
|
||||||
# `custom`, `checkpoints`, `debug`, `tasks`) are only present when their
|
# Always registered by `astream_events(version="v3")`:
|
||||||
# transformer is registered, so they are reached via `extensions[...]`.
|
|
||||||
values: StreamChannel[dict[str, Any]]
|
values: StreamChannel[dict[str, Any]]
|
||||||
messages: StreamChannel[AsyncChatModelStream]
|
messages: StreamChannel[AsyncChatModelStream]
|
||||||
lifecycle: StreamChannel[LifecyclePayload]
|
lifecycle: StreamChannel[LifecyclePayload]
|
||||||
subgraphs: StreamChannel[AsyncSubgraphRunStream]
|
subgraphs: StreamChannel[AsyncSubgraphRunStream]
|
||||||
|
# Registered on demand; see `GraphRunStream`.
|
||||||
|
updates: StreamChannel[dict[str, Any]]
|
||||||
|
custom: StreamChannel[Any]
|
||||||
|
checkpoints: StreamChannel[dict[str, Any]]
|
||||||
|
debug: StreamChannel[dict[str, Any]]
|
||||||
|
tasks: StreamChannel[dict[str, Any]]
|
||||||
|
|
||||||
|
def __getattr__(self, name: str) -> StreamChannel[Any]:
|
||||||
|
"""Type projections declared elsewhere. See `GraphRunStream`."""
|
||||||
|
_raise_missing_projection(self, name)
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
|||||||
@@ -12,15 +12,23 @@ from typing import (
|
|||||||
Generic,
|
Generic,
|
||||||
Literal,
|
Literal,
|
||||||
NamedTuple,
|
NamedTuple,
|
||||||
TypeVar,
|
|
||||||
final,
|
final,
|
||||||
|
overload,
|
||||||
)
|
)
|
||||||
from warnings import warn
|
from warnings import warn
|
||||||
|
|
||||||
from langchain_core.messages import AnyMessage
|
from langchain_core.messages import AnyMessage
|
||||||
from langchain_core.runnables import Runnable, RunnableConfig
|
from langchain_core.runnables import Runnable, RunnableConfig
|
||||||
from langgraph.checkpoint.base import BaseCheckpointSaver, CheckpointMetadata
|
from langgraph.checkpoint.base import BaseCheckpointSaver, CheckpointMetadata
|
||||||
from typing_extensions import NotRequired, TypeAliasType, TypedDict, Unpack, deprecated
|
from pydantic import TypeAdapter
|
||||||
|
from typing_extensions import (
|
||||||
|
NotRequired,
|
||||||
|
TypeAliasType,
|
||||||
|
TypedDict,
|
||||||
|
TypeVar,
|
||||||
|
Unpack,
|
||||||
|
deprecated,
|
||||||
|
)
|
||||||
from xxhash import xxh3_128_hexdigest
|
from xxhash import xxh3_128_hexdigest
|
||||||
|
|
||||||
from langgraph._internal._cache import default_cache_key
|
from langgraph._internal._cache import default_cache_key
|
||||||
@@ -36,6 +44,7 @@ from langgraph.warnings import LangGraphDeprecatedSinceV10, LangGraphDeprecatedS
|
|||||||
# when used in standalone type aliases.
|
# when used in standalone type aliases.
|
||||||
StateT = TypeVar("StateT")
|
StateT = TypeVar("StateT")
|
||||||
OutputT = TypeVar("OutputT")
|
OutputT = TypeVar("OutputT")
|
||||||
|
ResponseT = TypeVar("ResponseT", default=Any)
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from langgraph.pregel.protocol import PregelProtocol
|
from langgraph.pregel.protocol import PregelProtocol
|
||||||
@@ -70,6 +79,8 @@ __all__ = (
|
|||||||
"RetryPolicy",
|
"RetryPolicy",
|
||||||
"TimeoutPolicy",
|
"TimeoutPolicy",
|
||||||
"CachePolicy",
|
"CachePolicy",
|
||||||
|
"TracePolicy",
|
||||||
|
"omit_payload",
|
||||||
"Interrupt",
|
"Interrupt",
|
||||||
"StateUpdate",
|
"StateUpdate",
|
||||||
"PregelTask",
|
"PregelTask",
|
||||||
@@ -527,12 +538,50 @@ class CachePolicy(Generic[KeyFuncT]):
|
|||||||
"""Time to live for the cache entry in seconds. If `None`, the entry never expires."""
|
"""Time to live for the cache entry in seconds. If `None`, the entry never expires."""
|
||||||
|
|
||||||
|
|
||||||
|
@dataclass(**_DC_KWARGS)
|
||||||
|
class TracePolicy:
|
||||||
|
"""Configuration for how a node's run is traced.
|
||||||
|
|
||||||
|
Scope: this only transforms what the node's *own* run records. Child runs created
|
||||||
|
by a traced `bound` runnable and the root graph run are not affected. Plain
|
||||||
|
function nodes are traced with `trace=False`, so they have no such child runs.
|
||||||
|
|
||||||
|
Not intended to redact secrets. To redact inputs/outputs across all runs
|
||||||
|
(children included), use the LangSmith client's
|
||||||
|
`hide_inputs`/`hide_outputs`/`anonymizer` instead.
|
||||||
|
|
||||||
|
Each processor receives the node's raw input/output value (not a normalized
|
||||||
|
kwargs dict) and returns the value to record.
|
||||||
|
"""
|
||||||
|
|
||||||
|
process_inputs: Callable[[Any], Any] | None = None
|
||||||
|
"""Optional callable to transform the node's input before it is recorded on the
|
||||||
|
node's trace run. Can be used to omit or summarize large payloads
|
||||||
|
(e.g. message history). Not intended to affect the value passed to the node; avoid
|
||||||
|
mutating arguments in place."""
|
||||||
|
|
||||||
|
process_outputs: Callable[[Any], Any] | None = None
|
||||||
|
"""Optional callable to transform the node's output before it is recorded on the
|
||||||
|
node's trace run. Can be used to omit or summarize large payloads
|
||||||
|
(e.g. message history). Not intended to affect the value returned by the node; avoid
|
||||||
|
mutating arguments in place."""
|
||||||
|
|
||||||
|
|
||||||
|
def omit_payload(_value: Any) -> dict[str, Any]:
|
||||||
|
"""`TracePolicy` helper that records an empty payload, dropping the value entirely.
|
||||||
|
|
||||||
|
Use as `process_inputs` and/or `process_outputs` on a `TracePolicy` to keep a node's
|
||||||
|
span and its timing while omitting its inputs/outputs from the trace.
|
||||||
|
"""
|
||||||
|
return {}
|
||||||
|
|
||||||
|
|
||||||
_DEFAULT_INTERRUPT_ID = "placeholder-id"
|
_DEFAULT_INTERRUPT_ID = "placeholder-id"
|
||||||
|
|
||||||
|
|
||||||
@final
|
@final
|
||||||
@dataclass(init=False, slots=True)
|
@dataclass(init=False, slots=True)
|
||||||
class Interrupt:
|
class Interrupt(Generic[ResponseT]):
|
||||||
"""Information about an interrupt that occurred in a node.
|
"""Information about an interrupt that occurred in a node.
|
||||||
|
|
||||||
!!! version-added "Added in version 0.2.24"
|
!!! version-added "Added in version 0.2.24"
|
||||||
@@ -556,13 +605,22 @@ class Interrupt:
|
|||||||
id: str
|
id: str
|
||||||
"""The ID of the interrupt. Can be used to resume the interrupt directly."""
|
"""The ID of the interrupt. Can be used to resume the interrupt directly."""
|
||||||
|
|
||||||
|
response_schema: type[ResponseT] | dict[str, Any] | None = None
|
||||||
|
"""Schema for the value expected when resuming this interrupt, if the graph provided one.
|
||||||
|
|
||||||
|
A surfaced interrupt carries JSON Schema (a `dict`); `type[ResponseT]` records the
|
||||||
|
Python type at construction so `Interrupt[Decision]` is meaningful to type checkers."""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
value: Any,
|
value: Any,
|
||||||
id: str = _DEFAULT_INTERRUPT_ID,
|
id: str = _DEFAULT_INTERRUPT_ID,
|
||||||
|
*,
|
||||||
|
response_schema: type[ResponseT] | dict[str, Any] | None = None,
|
||||||
**deprecated_kwargs: Unpack[DeprecatedKwargs],
|
**deprecated_kwargs: Unpack[DeprecatedKwargs],
|
||||||
) -> None:
|
) -> None:
|
||||||
self.value = value
|
self.value = value
|
||||||
|
self.response_schema = response_schema
|
||||||
|
|
||||||
if (
|
if (
|
||||||
(ns := deprecated_kwargs.get("ns", MISSING)) is not MISSING
|
(ns := deprecated_kwargs.get("ns", MISSING)) is not MISSING
|
||||||
@@ -574,8 +632,18 @@ class Interrupt:
|
|||||||
self.id = id
|
self.id = id
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_ns(cls, value: Any, ns: str) -> Interrupt:
|
def from_ns(
|
||||||
return cls(value=value, id=xxh3_128_hexdigest(ns.encode()))
|
cls,
|
||||||
|
value: Any,
|
||||||
|
ns: str,
|
||||||
|
*,
|
||||||
|
response_schema: type[ResponseT] | dict[str, Any] | None = None,
|
||||||
|
) -> Interrupt[ResponseT]:
|
||||||
|
return cls(
|
||||||
|
value=value,
|
||||||
|
id=xxh3_128_hexdigest(ns.encode()),
|
||||||
|
response_schema=response_schema,
|
||||||
|
)
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@deprecated("`interrupt_id` is deprecated. Use `id` instead.", category=None)
|
@deprecated("`interrupt_id` is deprecated. Use `id` instead.", category=None)
|
||||||
@@ -808,7 +876,17 @@ class Command(Generic[N], ToolOutputMixin):
|
|||||||
PARENT: ClassVar[Literal["__parent__"]] = "__parent__"
|
PARENT: ClassVar[Literal["__parent__"]] = "__parent__"
|
||||||
|
|
||||||
|
|
||||||
def interrupt(value: Any) -> Any:
|
@overload
|
||||||
|
def interrupt(value: Any, *, response_schema: type[ResponseT]) -> ResponseT: ...
|
||||||
|
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def interrupt(value: Any, *, response_schema: dict[str, Any] | None = None) -> Any: ...
|
||||||
|
|
||||||
|
|
||||||
|
def interrupt(
|
||||||
|
value: Any, *, response_schema: dict[str, Any] | type | None = None
|
||||||
|
) -> Any:
|
||||||
"""Interrupt the graph with a resumable exception from within a node.
|
"""Interrupt the graph with a resumable exception from within a node.
|
||||||
|
|
||||||
The `interrupt` function enables human-in-the-loop workflows by pausing graph
|
The `interrupt` function enables human-in-the-loop workflows by pausing graph
|
||||||
@@ -878,7 +956,7 @@ def interrupt(value: Any) -> Any:
|
|||||||
for chunk in graph.stream({\"foo\": \"abc\"}, config):
|
for chunk in graph.stream({\"foo\": \"abc\"}, config):
|
||||||
print(chunk)
|
print(chunk)
|
||||||
|
|
||||||
# > {'__interrupt__': (Interrupt(value='what is your age?', id='45fda8478b2ef754419799e10992af06'),)}
|
# > {'__interrupt__': (Interrupt(value='what is your age?', id='45fda8478b2ef754419799e10992af06', response_schema=None),)}
|
||||||
|
|
||||||
command = Command(resume=\"some input from a human!!!\")
|
command = Command(resume=\"some input from a human!!!\")
|
||||||
|
|
||||||
@@ -891,12 +969,20 @@ def interrupt(value: Any) -> Any:
|
|||||||
|
|
||||||
Args:
|
Args:
|
||||||
value: The value to surface to the client when the graph is interrupted.
|
value: The value to surface to the client when the graph is interrupted.
|
||||||
|
response_schema: Optional schema for the value expected on resume, surfaced
|
||||||
|
to clients so they can render a typed input form. Accepts a JSON Schema
|
||||||
|
`dict` (used as-is, resume values are not validated), or a Pydantic model
|
||||||
|
class, `TypedDict`, or dataclass, which are converted to JSON Schema for
|
||||||
|
clients and used to validate the resume value; the validated object is
|
||||||
|
what `interrupt` returns.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
Any: On subsequent invocations within the same node (same task to be precise), returns the value provided during the first invocation
|
Any: On subsequent invocations within the same node (same task to be precise), returns the value provided during the first invocation,
|
||||||
|
validated against `response_schema` when one that supports validation was given.
|
||||||
|
|
||||||
Raises:
|
Raises:
|
||||||
GraphInterrupt: On the first invocation within the node, halts execution and surfaces the provided value to the client.
|
GraphInterrupt: On the first invocation within the node, halts execution and surfaces the provided value to the client.
|
||||||
|
pydantic.ValidationError: When a resume value does not match a Pydantic model, `TypedDict`, or dataclass `response_schema`.
|
||||||
"""
|
"""
|
||||||
from langgraph._internal._constants import (
|
from langgraph._internal._constants import (
|
||||||
CONFIG_KEY_CHECKPOINT_NS,
|
CONFIG_KEY_CHECKPOINT_NS,
|
||||||
@@ -908,27 +994,36 @@ def interrupt(value: Any) -> Any:
|
|||||||
from langgraph.errors import GraphInterrupt
|
from langgraph.errors import GraphInterrupt
|
||||||
|
|
||||||
conf = get_config()["configurable"]
|
conf = get_config()["configurable"]
|
||||||
|
adapter = (
|
||||||
|
None
|
||||||
|
if response_schema is None or isinstance(response_schema, dict)
|
||||||
|
else TypeAdapter(response_schema)
|
||||||
|
)
|
||||||
# track interrupt index
|
# track interrupt index
|
||||||
scratchpad = conf[CONFIG_KEY_SCRATCHPAD]
|
scratchpad = conf[CONFIG_KEY_SCRATCHPAD]
|
||||||
idx = scratchpad.interrupt_counter()
|
idx = scratchpad.interrupt_counter()
|
||||||
# find previous resume values
|
# find previous resume values
|
||||||
if scratchpad.resume:
|
if scratchpad.resume:
|
||||||
if idx < len(scratchpad.resume):
|
if idx < len(scratchpad.resume):
|
||||||
conf[CONFIG_KEY_SEND]([(RESUME, scratchpad.resume)])
|
v = scratchpad.resume[idx]
|
||||||
return scratchpad.resume[idx]
|
validated = adapter.validate_python(v) if adapter else v
|
||||||
|
conf[CONFIG_KEY_SEND]([(RESUME, scratchpad.resume[: idx + 1])])
|
||||||
|
return validated
|
||||||
# find current resume value
|
# find current resume value
|
||||||
v = scratchpad.get_null_resume(True)
|
v = scratchpad.get_null_resume(True)
|
||||||
if v is not None:
|
if v is not None:
|
||||||
assert len(scratchpad.resume) == idx, (scratchpad.resume, idx)
|
assert len(scratchpad.resume) == idx, (scratchpad.resume, idx)
|
||||||
|
validated = adapter.validate_python(v) if adapter else v
|
||||||
scratchpad.resume.append(v)
|
scratchpad.resume.append(v)
|
||||||
conf[CONFIG_KEY_SEND]([(RESUME, scratchpad.resume)])
|
conf[CONFIG_KEY_SEND]([(RESUME, scratchpad.resume)])
|
||||||
return v
|
return validated
|
||||||
# no resume value found
|
# no resume value found
|
||||||
raise GraphInterrupt(
|
raise GraphInterrupt(
|
||||||
(
|
(
|
||||||
Interrupt.from_ns(
|
Interrupt.from_ns(
|
||||||
value=value,
|
value=value,
|
||||||
ns=conf[CONFIG_KEY_CHECKPOINT_NS],
|
ns=conf[CONFIG_KEY_CHECKPOINT_NS],
|
||||||
|
response_schema=adapter.json_schema() if adapter else response_schema,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|||||||
|
|
||||||
[project]
|
[project]
|
||||||
name = "langgraph"
|
name = "langgraph"
|
||||||
version = "1.2.10"
|
version = "1.2.12"
|
||||||
description = "Building stateful, multi-actor applications with LLMs"
|
description = "Building stateful, multi-actor applications with LLMs"
|
||||||
authors = []
|
authors = []
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10"
|
||||||
@@ -89,8 +89,12 @@ langgraph-sdk = { path = "../sdk-py", editable = true }
|
|||||||
langgraph-cli = { path = "../cli", editable = true }
|
langgraph-cli = { path = "../cli", editable = true }
|
||||||
|
|
||||||
[tool.ruff]
|
[tool.ruff]
|
||||||
lint.select = [ "E", "F", "I", "TID251", "UP" ]
|
lint.select = [ "E", "F", "I", "PLC0415", "RUF100", "TID251", "UP" ]
|
||||||
lint.ignore = [ "E501" ]
|
lint.ignore = [ "E501" ]
|
||||||
|
# PLC0415 (import-outside-top-level) is enforced in tests only. Library code
|
||||||
|
# still has deferred imports that have not been reviewed, so it stays exempt
|
||||||
|
# for now.
|
||||||
|
lint.per-file-ignores = { "langgraph/**" = ["PLC0415"] }
|
||||||
line-length = 88
|
line-length = 88
|
||||||
indent-width = 4
|
indent-width = 4
|
||||||
extend-include = ["*.ipynb"]
|
extend-include = ["*.ipynb"]
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user