From 1a06d500d4282cfdb2ae9d7748bb570e8162acdf Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 16:08:57 -0400 Subject: [PATCH 01/27] libs: add cli, sdk-py, sdk-js and move core langgraph --- .github/workflows/release.yml | 2 +- LICENSE | 2 +- Makefile | 69 +- libs/cli/LICENSE | 21 + libs/cli/Makefile | 13 + libs/cli/README.md | 3 + .../cli/langgraph_cli}/__init__.py | 0 libs/cli/langgraph_cli/cli.py | 476 ++++++++++++ libs/cli/langgraph_cli/config.py | 306 ++++++++ libs/cli/langgraph_cli/docker.py | 162 ++++ libs/cli/langgraph_cli/exec.py | 140 ++++ libs/cli/langgraph_cli/progress.py | 64 ++ libs/cli/poetry.lock | 327 ++++++++ libs/cli/pyproject.toml | 53 ++ .../serde => libs/cli/tests}/__init__.py | 0 .../cli/tests/unit_tests}/__init__.py | 0 .../cli/tests/unit_tests/agent.py | 0 .../cli/tests/unit_tests/graphs/agent.py | 0 libs/cli/tests/unit_tests/helpers.py | 2 + libs/cli/tests/unit_tests/test_cli.py | 113 +++ libs/cli/tests/unit_tests/test_config.json | 13 + libs/cli/tests/unit_tests/test_config.py | 396 ++++++++++ libs/cli/tests/unit_tests/test_docker.py | 114 +++ libs/langgraph/LICENSE | 21 + libs/langgraph/Makefile | 70 ++ .../langgraph/langgraph}/__init__.py | 0 libs/langgraph/langgraph/_api/__init__.py | 0 .../langgraph/langgraph}/_api/deprecation.py | 0 .../langgraph/langgraph}/channels/__init__.py | 0 .../langgraph}/channels/any_value.py | 0 .../langgraph/langgraph}/channels/base.py | 0 .../langgraph/langgraph}/channels/binop.py | 0 .../langgraph/langgraph}/channels/context.py | 0 .../channels/dynamic_barrier_value.py | 0 .../langgraph}/channels/ephemeral_value.py | 0 .../langgraph}/channels/last_value.py | 0 .../langgraph/langgraph}/channels/manager.py | 0 .../channels/named_barrier_value.py | 0 .../langgraph/langgraph}/channels/topic.py | 0 .../langgraph}/checkpoint/__init__.py | 0 .../langgraph}/checkpoint/aiosqlite.py | 0 .../langgraph/langgraph}/checkpoint/base.py | 0 .../langgraph/langgraph}/checkpoint/id.py | 0 .../langgraph/langgraph}/checkpoint/memory.py | 0 .../langgraph/langgraph}/checkpoint/sqlite.py | 0 .../langgraph/langgraph}/constants.py | 0 .../langgraph/langgraph}/errors.py | 0 .../langgraph/langgraph}/graph/__init__.py | 0 .../langgraph/langgraph}/graph/graph.py | 0 .../langgraph/langgraph}/graph/message.py | 0 .../langgraph/langgraph}/graph/state.py | 0 .../langgraph/langgraph}/managed/__init__.py | 0 .../langgraph/langgraph}/managed/base.py | 0 .../langgraph/langgraph}/managed/few_shot.py | 0 .../langgraph}/managed/is_last_step.py | 0 .../langgraph/langgraph}/prebuilt/__init__.py | 0 .../langgraph}/prebuilt/agent_executor.py | 0 .../prebuilt/chat_agent_executor.py | 0 .../langgraph}/prebuilt/tool_executor.py | 0 .../langgraph}/prebuilt/tool_node.py | 0 .../langgraph}/prebuilt/tool_validator.py | 0 .../langgraph/langgraph}/pregel/__init__.py | 0 .../langgraph/langgraph}/pregel/debug.py | 0 .../langgraph/langgraph}/pregel/io.py | 0 .../langgraph/langgraph}/pregel/log.py | 0 .../langgraph/langgraph}/pregel/read.py | 0 .../langgraph/langgraph}/pregel/retry.py | 0 .../langgraph/langgraph}/pregel/types.py | 0 .../langgraph/langgraph}/pregel/validate.py | 0 .../langgraph/langgraph}/pregel/write.py | 0 libs/langgraph/langgraph/py.typed | 0 libs/langgraph/langgraph/serde/__init__.py | 0 .../langgraph/langgraph}/serde/base.py | 0 .../langgraph/langgraph}/serde/jsonplus.py | 0 .../langgraph/langgraph}/utils.py | 0 .../langgraph/langgraph}/version.py | 0 poetry.lock => libs/langgraph/poetry.lock | 0 poetry.toml => libs/langgraph/poetry.toml | 0 .../langgraph/pyproject.toml | 0 libs/langgraph/tests/__init__.py | 0 .../tests}/__snapshots__/test_pregel.ambr | 0 .../__snapshots__/test_pregel_async.ambr | 0 {tests => libs/langgraph/tests}/any_str.py | 0 libs/langgraph/tests/checkpoint/__init__.py | 0 .../tests}/checkpoint/test_aiosqlite.py | 0 .../tests}/checkpoint/test_memory.py | 0 .../tests}/checkpoint/test_sqlite.py | 0 {tests => libs/langgraph/tests}/conftest.py | 0 .../langgraph/tests}/memory_assert.py | 0 .../langgraph/tests}/test_channels.py | 0 {tests => libs/langgraph/tests}/test_io.py | 0 .../langgraph/tests}/test_jsonplus.py | 0 .../langgraph/tests}/test_prebuilt.py | 0 .../langgraph/tests}/test_pregel.py | 0 .../langgraph/tests}/test_pregel_async.py | 0 {tests => libs/langgraph/tests}/test_state.py | 0 {tests => libs/langgraph/tests}/test_utils.py | 0 libs/sdk-js/LICENSE | 21 + libs/sdk-js/client.cjs | 1 + libs/sdk-js/client.d.cts | 1 + libs/sdk-js/client.d.ts | 1 + libs/sdk-js/client.js | 1 + libs/sdk-js/index.cjs | 1 + libs/sdk-js/index.d.cts | 1 + libs/sdk-js/index.d.ts | 1 + libs/sdk-js/index.js | 1 + libs/sdk-js/package.json | 64 ++ libs/sdk-js/scripts/create-entrypoints.js | 115 +++ libs/sdk-js/scripts/move-cjs-to-dist.js | 38 + libs/sdk-js/src/client.mts | 713 ++++++++++++++++++ libs/sdk-js/src/index.mts | 14 + libs/sdk-js/src/schema.ts | 108 +++ libs/sdk-js/src/types.mts | 86 +++ libs/sdk-js/src/utils/async_caller.mts | 206 +++++ libs/sdk-js/src/utils/stream.mts | 109 +++ libs/sdk-js/tsconfig.cjs.json | 7 + libs/sdk-js/tsconfig.json | 26 + libs/sdk-js/yarn.lock | 93 +++ libs/sdk-py/LICENSE | 21 + libs/sdk-py/Makefile | 10 + libs/sdk-py/README.md | 1 + libs/sdk-py/langgraph_sdk/__init__.py | 10 + libs/sdk-py/langgraph_sdk/client.py | 610 +++++++++++++++ libs/sdk-py/langgraph_sdk/schema.py | 128 ++++ libs/sdk-py/poetry.lock | 492 ++++++++++++ libs/sdk-py/pyproject.toml | 47 ++ 126 files changed, 5224 insertions(+), 70 deletions(-) create mode 100644 libs/cli/LICENSE create mode 100644 libs/cli/Makefile create mode 100644 libs/cli/README.md rename {langgraph/_api => libs/cli/langgraph_cli}/__init__.py (100%) create mode 100644 libs/cli/langgraph_cli/cli.py create mode 100644 libs/cli/langgraph_cli/config.py create mode 100644 libs/cli/langgraph_cli/docker.py create mode 100644 libs/cli/langgraph_cli/exec.py create mode 100644 libs/cli/langgraph_cli/progress.py create mode 100644 libs/cli/poetry.lock create mode 100644 libs/cli/pyproject.toml rename {langgraph/serde => libs/cli/tests}/__init__.py (100%) rename {tests => libs/cli/tests/unit_tests}/__init__.py (100%) rename langgraph/py.typed => libs/cli/tests/unit_tests/agent.py (100%) rename tests/checkpoint/__init__.py => libs/cli/tests/unit_tests/graphs/agent.py (100%) create mode 100644 libs/cli/tests/unit_tests/helpers.py create mode 100644 libs/cli/tests/unit_tests/test_cli.py create mode 100644 libs/cli/tests/unit_tests/test_config.json create mode 100644 libs/cli/tests/unit_tests/test_config.py create mode 100644 libs/cli/tests/unit_tests/test_docker.py create mode 100644 libs/langgraph/LICENSE create mode 100644 libs/langgraph/Makefile rename {langgraph => libs/langgraph/langgraph}/__init__.py (100%) create mode 100644 libs/langgraph/langgraph/_api/__init__.py rename {langgraph => libs/langgraph/langgraph}/_api/deprecation.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/any_value.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/base.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/binop.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/context.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/dynamic_barrier_value.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/ephemeral_value.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/last_value.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/manager.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/named_barrier_value.py (100%) rename {langgraph => libs/langgraph/langgraph}/channels/topic.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/aiosqlite.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/base.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/id.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/memory.py (100%) rename {langgraph => libs/langgraph/langgraph}/checkpoint/sqlite.py (100%) rename {langgraph => libs/langgraph/langgraph}/constants.py (100%) rename {langgraph => libs/langgraph/langgraph}/errors.py (100%) rename {langgraph => libs/langgraph/langgraph}/graph/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/graph/graph.py (100%) rename {langgraph => libs/langgraph/langgraph}/graph/message.py (100%) rename {langgraph => libs/langgraph/langgraph}/graph/state.py (100%) rename {langgraph => libs/langgraph/langgraph}/managed/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/managed/base.py (100%) rename {langgraph => libs/langgraph/langgraph}/managed/few_shot.py (100%) rename {langgraph => libs/langgraph/langgraph}/managed/is_last_step.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/agent_executor.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/chat_agent_executor.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/tool_executor.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/tool_node.py (100%) rename {langgraph => libs/langgraph/langgraph}/prebuilt/tool_validator.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/__init__.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/debug.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/io.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/log.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/read.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/retry.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/types.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/validate.py (100%) rename {langgraph => libs/langgraph/langgraph}/pregel/write.py (100%) create mode 100644 libs/langgraph/langgraph/py.typed create mode 100644 libs/langgraph/langgraph/serde/__init__.py rename {langgraph => libs/langgraph/langgraph}/serde/base.py (100%) rename {langgraph => libs/langgraph/langgraph}/serde/jsonplus.py (100%) rename {langgraph => libs/langgraph/langgraph}/utils.py (100%) rename {langgraph => libs/langgraph/langgraph}/version.py (100%) rename poetry.lock => libs/langgraph/poetry.lock (100%) rename poetry.toml => libs/langgraph/poetry.toml (100%) rename pyproject.toml => libs/langgraph/pyproject.toml (100%) create mode 100644 libs/langgraph/tests/__init__.py rename {tests => libs/langgraph/tests}/__snapshots__/test_pregel.ambr (100%) rename {tests => libs/langgraph/tests}/__snapshots__/test_pregel_async.ambr (100%) rename {tests => libs/langgraph/tests}/any_str.py (100%) create mode 100644 libs/langgraph/tests/checkpoint/__init__.py rename {tests => libs/langgraph/tests}/checkpoint/test_aiosqlite.py (100%) rename {tests => libs/langgraph/tests}/checkpoint/test_memory.py (100%) rename {tests => libs/langgraph/tests}/checkpoint/test_sqlite.py (100%) rename {tests => libs/langgraph/tests}/conftest.py (100%) rename {tests => libs/langgraph/tests}/memory_assert.py (100%) rename {tests => libs/langgraph/tests}/test_channels.py (100%) rename {tests => libs/langgraph/tests}/test_io.py (100%) rename {tests => libs/langgraph/tests}/test_jsonplus.py (100%) rename {tests => libs/langgraph/tests}/test_prebuilt.py (100%) rename {tests => libs/langgraph/tests}/test_pregel.py (100%) rename {tests => libs/langgraph/tests}/test_pregel_async.py (100%) rename {tests => libs/langgraph/tests}/test_state.py (100%) rename {tests => libs/langgraph/tests}/test_utils.py (100%) create mode 100644 libs/sdk-js/LICENSE create mode 100644 libs/sdk-js/client.cjs create mode 100644 libs/sdk-js/client.d.cts create mode 100644 libs/sdk-js/client.d.ts create mode 100644 libs/sdk-js/client.js create mode 100644 libs/sdk-js/index.cjs create mode 100644 libs/sdk-js/index.d.cts create mode 100644 libs/sdk-js/index.d.ts create mode 100644 libs/sdk-js/index.js create mode 100644 libs/sdk-js/package.json create mode 100644 libs/sdk-js/scripts/create-entrypoints.js create mode 100644 libs/sdk-js/scripts/move-cjs-to-dist.js create mode 100644 libs/sdk-js/src/client.mts create mode 100644 libs/sdk-js/src/index.mts create mode 100644 libs/sdk-js/src/schema.ts create mode 100644 libs/sdk-js/src/types.mts create mode 100644 libs/sdk-js/src/utils/async_caller.mts create mode 100644 libs/sdk-js/src/utils/stream.mts create mode 100644 libs/sdk-js/tsconfig.cjs.json create mode 100644 libs/sdk-js/tsconfig.json create mode 100644 libs/sdk-js/yarn.lock create mode 100644 libs/sdk-py/LICENSE create mode 100644 libs/sdk-py/Makefile create mode 100644 libs/sdk-py/README.md create mode 100644 libs/sdk-py/langgraph_sdk/__init__.py create mode 100644 libs/sdk-py/langgraph_sdk/client.py create mode 100644 libs/sdk-py/langgraph_sdk/schema.py create mode 100644 libs/sdk-py/poetry.lock create mode 100644 libs/sdk-py/pyproject.toml diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5bb9dace2..1ce24c0df 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -133,7 +133,7 @@ jobs: "$PKG_NAME==$VERSION" - name: Run unit tests - run: make tests + run: make test publish: needs: diff --git a/LICENSE b/LICENSE index 395773867..fc0602fee 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) LangChain, Inc. +Copyright (c) 2024 LangChain, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index 3b2ae1774..f2216a7ce 100644 --- a/Makefile +++ b/Makefile @@ -1,48 +1,5 @@ .PHONY: all clean format lint test tests test_watch integration_tests docker_tests help extended_tests coverage spell_check spell_fix build-docs serve-docs serve-clean-docs clean-docs -# Default target executed when no arguments are given to make. -all: help - -###################### -# TESTING AND COVERAGE -###################### - -# Run unit tests and generate a coverage report. -coverage: - poetry run pytest --cov \ - --cov-config=.coveragerc \ - --cov-report xml \ - --cov-report term-missing:skip-covered - -test: - poetry run pytest - -test_watch: - poetry run ptw . - -###################### -# LINTING AND FORMATTING -###################### - -# Define a variable for Python and notebook files. -PYTHON_FILES=. -MYPY_CACHE=.mypy_cache -lint format: PYTHON_FILES=. -lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') -lint_package: PYTHON_FILES=langgraph -lint_tests: PYTHON_FILES=tests -lint_tests: MYPY_CACHE=.mypy_cache_test - -lint lint_diff lint_package lint_tests: - poetry run ruff . - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff - [ "$(PYTHON_FILES)" = "" ] || poetry run ruff --select I $(PYTHON_FILES) - [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) || poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) - -format format_diff: - poetry run ruff format $(PYTHON_FILES) - poetry run ruff --select I --fix $(PYTHON_FILES) - spell_check: poetry run codespell --toml pyproject.toml @@ -63,28 +20,4 @@ serve-docs: clean-docs: find ./docs/docs -name "*.ipynb" -type f -delete - rm -rf docs/site - - -###################### -# HELP -###################### - -help: - @echo '====================' - @echo '-- DOCUMENTATION --' - - @echo '-- LINTING --' - @echo 'format - run code formatters' - @echo 'lint - run linters' - @echo 'spell_check - run codespell on the project' - @echo 'spell_fix - run codespell on the project and fix the errors' - @echo '-- TESTS --' - @echo 'coverage - run unit tests and generate coverage report' - @echo 'test - run unit tests' - @echo 'tests - run unit tests (alias for "make test")' - @echo 'test TEST_FILE= - run all tests in file' - @echo 'extended_tests - run only extended unit tests' - @echo 'test_watch - run unit tests in watch mode' - @echo 'integration_tests - run integration tests' - @echo 'docker_tests - run unit tests in docker' + rm -rf docs/site \ No newline at end of file diff --git a/libs/cli/LICENSE b/libs/cli/LICENSE new file mode 100644 index 000000000..fc0602fee --- /dev/null +++ b/libs/cli/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/cli/Makefile b/libs/cli/Makefile new file mode 100644 index 000000000..0bb0d74da --- /dev/null +++ b/libs/cli/Makefile @@ -0,0 +1,13 @@ +.PHONY: lint format + +lint: + poetry run ruff . + poetry run ruff format . --diff + poetry run mypy . + +format: + poetry run ruff format . + poetry run ruff --select I --fix . + +test: + poetry run pytest tests \ No newline at end of file diff --git a/libs/cli/README.md b/libs/cli/README.md new file mode 100644 index 000000000..b65ad64ac --- /dev/null +++ b/libs/cli/README.md @@ -0,0 +1,3 @@ +# langchain-cli + +This package implements the official CLI for LangGraph API. \ No newline at end of file diff --git a/langgraph/_api/__init__.py b/libs/cli/langgraph_cli/__init__.py similarity index 100% rename from langgraph/_api/__init__.py rename to libs/cli/langgraph_cli/__init__.py diff --git a/libs/cli/langgraph_cli/cli.py b/libs/cli/langgraph_cli/cli.py new file mode 100644 index 000000000..69d66c75d --- /dev/null +++ b/libs/cli/langgraph_cli/cli.py @@ -0,0 +1,476 @@ +import json +import pathlib +import shutil +import sys +from typing import Optional + +import click +import click.exceptions + +import langgraph_cli.config +import langgraph_cli.docker +from langgraph_cli.config import Config +from langgraph_cli.docker import DockerCapabilities +from langgraph_cli.exec import Runner, subp_exec +from langgraph_cli.progress import Progress + +OPT_O = click.option( + "--docker-compose", + "-d", + help="Advanced: Path to docker-compose.yml file with additional services to launch", + type=click.Path( + exists=True, + file_okay=True, + dir_okay=False, + resolve_path=True, + path_type=pathlib.Path, + ), +) +OPT_C = click.option( + "--config", + "-c", + help="""Path to configuration file declaring dependencies, graphs and environment variables. + + \b + Config file must be a JSON file that has the following keys: + - "dependencies": array of dependencies for langgraph API server. Dependencies can be one of the following: + - ".", which would look for local python packages, as well as pyproject.toml, setup.py or requirements.txt in the app directory + - "./local_package" + - " + - "graphs": mapping from graph ID to path where the compiled graph is defined, i.e. ./your_package/your_file.py:variable, where + "variable" is an instance of langgraph.graph.graph.CompiledGraph + - "env": (optional) path to .env file or a mapping from environment variable to its value + - "python_version": (optional) 3.11 or 3.12. Defaults to 3.11 + - "pip_config_file": (optional) path to pip config file + - "dockerfile_lines": (optional) array of additional lines to add to Dockerfile following the import from parent image + + \b + Example: + langgraph up -c langgraph.json + + \b + Example: + { + "dependencies": [ + "langchain_openai", + "./your_package" + ], + "graphs": { + "my_graph_id": "./your_package/your_file.py:variable" + }, + "env": "./.env" + } + + \b + Example: + { + "python_version": "3.11", + "dependencies": [ + "langchain_openai", + "." + ], + "graphs": { + "my_graph_id": "./your_package/your_file.py:variable" + }, + "env": { + "OPENAI_API_KEY": "secret-key" + } + } + + Defaults to looking for langgraph.json in the current directory.""", + default="langgraph.json", + type=click.Path( + exists=True, + file_okay=True, + dir_okay=False, + resolve_path=True, + path_type=pathlib.Path, + ), +) +OPT_PORT = click.option( + "--port", + "-p", + type=int, + default=8123, + show_default=True, + help=""" + Port to expose. + + \b + Example: + langgraph up --port 8000 + \b + """, +) +OPT_RECREATE = click.option( + "--recreate/--no-recreate", + default=False, + show_default=True, + help="Recreate containers even if their configuration and image haven't changed", +) +OPT_PULL = click.option( + "--pull/--no-pull", + default=True, + show_default=True, + help=""" + Pull latest images. Use --no-pull for running the server with locally-built images. + + \b + Example: + langgraph up --no-pull + \b + """, +) +OPT_VERBOSE = click.option( + "--verbose", + is_flag=True, + default=False, + help="Show more output from the server logs", +) +OPT_DEBUGGER_PORT = click.option( + "--debugger-port", + type=int, + help="Pull the debugger image locally and serve the UI on specified port", +) + + +@click.group() +def cli(): + pass + + +@OPT_RECREATE +@OPT_PULL +@OPT_PORT +@OPT_O +@OPT_C +@OPT_VERBOSE +@OPT_DEBUGGER_PORT +@click.option("--watch", is_flag=True, help="Restart on file changes") +@click.option( + "--langgraph-api-path", + type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), + hidden=True, +) +@click.option( + "--wait", + is_flag=True, + help="Wait for services to start before returning. Implies --detach", +) +@cli.command(help="Start langgraph API server") +def up( + config: pathlib.Path, + docker_compose: Optional[pathlib.Path], + port: int, + recreate: bool, + pull: bool, + watch: bool, + langgraph_api_path: Optional[pathlib.Path], + wait: bool, + verbose: bool, + debugger_port: Optional[int], +): + with Runner() as runner, Progress(message="Pulling...") as set: + capabilities = langgraph_cli.docker.check_capabilities(runner) + args, stdin = prepare( + runner, + capabilities=capabilities, + config_path=config, + docker_compose=docker_compose, + port=port, + pull=pull, + watch=watch, + langgraph_api_path=langgraph_api_path, + verbose=verbose, + debugger_port=debugger_port, + ) + # add up + options + args.extend(["up", "--remove-orphans"]) + if recreate: + args.extend(["--force-recreate", "--renew-anon-volumes"]) + shutil.rmtree(config.parent / ".langgraph-data", ignore_errors=True) + try: + runner.run(subp_exec("docker", "volume", "rm", "langgraph-data")) + except click.exceptions.Exit: + pass + if watch: + args.append("--watch") + if wait: + args.append("--wait") + # run docker compose + set("Building...") + + def on_stdout(line: str): + if "unpacking to docker.io" in line: + set("Starting...") + elif "GET /ok" in line: + debugger_origin = ( + f"http://localhost:{debugger_port}" + if debugger_port + else "https://dev.smith.langchain.com" + ) + set("") + sys.stdout.write( + f"""Ready! +- API: http://localhost:{port} +- Docs: http://localhost:{port}/docs +- Debugger: {debugger_origin}/studio/?baseUrl=http://127.0.0.1:{port} +""" + ) + sys.stdout.flush() + return True + + if capabilities.compose_type == "plugin": + compose_cmd = ["docker", "compose"] + elif capabilities.compose_type == "standalone": + compose_cmd = ["docker-compose"] + + runner.run( + subp_exec( + *compose_cmd, + *args, + input=stdin, + verbose=verbose, + on_stdout=on_stdout, + ) + ) + + +@OPT_PORT +@OPT_O +@OPT_C +@OPT_VERBOSE +@OPT_DEBUGGER_PORT +@cli.command(help="Stop langgraph API server") +def down( + config: pathlib.Path, + docker_compose: Optional[pathlib.Path], + port: int, + verbose: bool, + debugger_port: Optional[int], +): + with Runner() as runner: + capabilities = langgraph_cli.docker.check_capabilities(runner) + args, stdin = prepare( + runner, + capabilities=capabilities, + config_path=config, + docker_compose=docker_compose, + port=port, + pull=False, + watch=False, + langgraph_api_path=None, + verbose=verbose, + debugger_port=debugger_port, + ) + # add down + options + args.append("down") + # run docker compose + if capabilities.compose_type == "plugin": + compose_cmd = ["docker", "compose"] + elif capabilities.compose_type == "standalone": + compose_cmd = ["docker-compose"] + + runner.run(subp_exec(*compose_cmd, *args, input=stdin, verbose=verbose)) + + +@OPT_O +@OPT_C +@click.option("--follow", "-f", is_flag=True, help="Follow logs") +@cli.command(help="Show langgraph API server logs") +def logs( + config: pathlib.Path, + docker_compose: Optional[pathlib.Path], + follow: bool, +): + with Runner() as runner: + capabilities = langgraph_cli.docker.check_capabilities(runner) + args, stdin = prepare( + runner, + capabilities=capabilities, + config_path=config, + docker_compose=docker_compose, + port=8123, + pull=False, + watch=False, + verbose=False, + langgraph_api_path=None, + ) + # add logs + options + args.append("logs") + if follow: + args.extend(["-f"]) + # run docker compose + if capabilities.compose_type == "plugin": + compose_cmd = ["docker", "compose"] + elif capabilities.compose_type == "standalone": + compose_cmd = ["docker-compose"] + + runner.run(subp_exec(*compose_cmd, *args, input=stdin, verbose=True)) + + +@OPT_C +@OPT_PULL +@click.option( + "--tag", + "-t", + help="""Tag for the docker image. + + \b + Example: + langgraph build -t my-image + + \b + """, + required=True, +) +@click.option( + "--platform", + help="""Target platform(s) to build the docker image for. + + \b + Example: + langgraph build --platform linux/amd64,linux/arm64 + \b + """, +) +@cli.command(help="Build langgraph API server docker image") +def build( + config: pathlib.Path, + platform: Optional[str], + pull: bool, + tag: str, +): + with open(config) as f: + config_json = langgraph_cli.config.validate_config(json.load(f)) + with Runner() as runner: + # check docker available + langgraph_cli.docker.check_capabilities(runner) + # pull latest images + if pull: + runner.run( + subp_exec( + "docker", + "pull", + f"langchain/langgraph-api:{config_json['python_version']}", + ) + ) + # apply options + args = [ + "-f", + "-", # stdin + "-t", + tag, + ] + if platform: + args.extend(["--platform", platform]) + # apply config + stdin = langgraph_cli.config.config_to_docker(config, config_json) + # run docker build + runner.run( + subp_exec( + "docker", "build", *args, str(config.parent), input=stdin, verbose=True + ) + ) + + +@OPT_PORT +@OPT_O +@OPT_C +@cli.command(help="Build a helm chart to deploy to a Kubernetes cluster", hidden=True) +def helm( + config: pathlib.Path, + docker_compose: Optional[pathlib.Path], + port: int, +): + with open(config) as f: + config_json = langgraph_cli.config.validate_config(json.load(f)) + with Runner() as runner: + # check docker available + capabilities = langgraph_cli.docker.check_capabilities(runner) + # prepare args + stdin = langgraph_cli.docker.compose(capabilities, port=port) + args = [ + "--chart", + "-o=./helm", + "-v", + "-f", + "-", # stdin + ] + # apply options + if docker_compose: + args.extend(["-f", str(docker_compose)]) + args.append("convert") + # apply config + stdin += langgraph_cli.config.config_to_compose(config, config_json) + # run kompose convert + runner.run(subp_exec("kompose", *args, input=stdin)) + + +def prepare_args_and_stdin( + *, + capabilities: DockerCapabilities, + config_path: pathlib.Path, + config: Config, + docker_compose: Optional[pathlib.Path], + port: int, + watch: bool, + langgraph_api_path: Optional[pathlib.Path], + debugger_port: Optional[int] = None, +): + # prepare args + stdin = langgraph_cli.docker.compose( + capabilities, port=port, debugger_port=debugger_port + ) + args = [ + "--project-directory", + str(config_path.parent), + ] + # apply options + if docker_compose: + args.extend(["-f", str(docker_compose)]) + args.extend(["-f", "-"]) # stdin + # apply config + stdin += langgraph_cli.config.config_to_compose( + config_path, config, watch=watch, langgraph_api_path=langgraph_api_path + ) + return args, stdin + + +def prepare( + runner, + *, + capabilities: DockerCapabilities, + config_path: pathlib.Path, + docker_compose: Optional[pathlib.Path], + port: int, + pull: bool, + watch: bool, + langgraph_api_path: Optional[pathlib.Path], + verbose: bool, + debugger_port: Optional[int] = None, +): + with open(config_path) as f: + config = langgraph_cli.config.validate_config(json.load(f)) + # pull latest images + if pull: + runner.run( + subp_exec( + "docker", + "pull", + f"langchain/langgraph-api:{config['python_version']}", + verbose=verbose, + ) + ) + + args, stdin = prepare_args_and_stdin( + capabilities=capabilities, + config_path=config_path, + config=config, + docker_compose=docker_compose, + port=port, + watch=watch, + langgraph_api_path=langgraph_api_path, + debugger_port=debugger_port, + ) + return args, stdin diff --git a/libs/cli/langgraph_cli/config.py b/libs/cli/langgraph_cli/config.py new file mode 100644 index 000000000..47ba78756 --- /dev/null +++ b/libs/cli/langgraph_cli/config.py @@ -0,0 +1,306 @@ +import json +import os +import pathlib +import textwrap +from typing import NamedTuple, Optional, TypedDict, Union + +import click + + +class Config(TypedDict): + python_version: str + pip_config_file: Optional[str] + dockerfile_lines: list[str] + dependencies: list[str] + graphs: dict[str, str] + env: Union[dict[str, str], str] + + +def validate_config(config: Config) -> Config: + config = { + "python_version": config.get("python_version", "3.11"), + "pip_config_file": config.get("pip_config_file"), + "dockerfile_lines": config.get("dockerfile_lines", []), + "dependencies": config.get("dependencies", []), + "graphs": config.get("graphs", {}), + "env": config.get("env", {}), + } + if config["python_version"] not in ( + "3.11", + "3.12", + ): + raise click.UsageError( + f"Unsupported Python version: {config['python_version']}. " + "Supported versions are 3.11 and 3.12." + ) + if not config["dependencies"]: + raise click.UsageError( + "No dependencies found in config. " + "Add at least one dependency to 'dependencies' list." + ) + if not config["graphs"]: + raise click.UsageError( + "No graphs found in config. " + "Add at least one graph to 'graphs' dictionary." + ) + return config + + +class LocalDeps(NamedTuple): + pip_reqs: list[tuple[pathlib.Path, str]] + real_pkgs: dict[pathlib.Path, str] + faux_pkgs: dict[pathlib.Path, tuple[str, str]] + # if . is in dependencies, use it as working_dir + working_dir: Optional[str] = None + + +def _assemble_local_deps(config_path: pathlib.Path, config: Config) -> LocalDeps: + # ensure reserved package names are not used + reserved = { + "src", + "langgraph-api", + "langgraph_api", + "langgraph", + "langchain-core", + "langchain_core", + "pydantic", + "orjson", + "fastapi", + "uvicorn", + "psycopg", + "httpx", + "langsmith", + } + + def check_reserved(name: str, ref: str): + if name in reserved: + raise ValueError( + f"Package name '{name}' used in local dep '{ref}' is reserved. " + "Rename the directory." + ) + reserved.add(name) + + pip_reqs = [] + real_pkgs = {} + faux_pkgs = {} + working_dir = None + + for local_dep in config["dependencies"]: + if not local_dep.startswith("."): + continue + + resolved = config_path.parent / local_dep + + # validate local dependency + if not resolved.exists(): + raise FileNotFoundError(f"Could not find local dependency: {resolved}") + elif not resolved.is_dir(): + raise NotADirectoryError( + f"Local dependency must be a directory: {resolved}" + ) + elif not resolved.is_relative_to(config_path.parent): + raise ValueError( + f"Local dependency '{resolved}' must be a subdirectory of '{config_path.parent}'" + ) + + # if it's installable, add it to local_pkgs + # otherwise, add it to faux_pkgs, and create a pyproject.toml + files = os.listdir(resolved) + if "pyproject.toml" in files: + real_pkgs[resolved] = local_dep + if local_dep == ".": + working_dir = f"/deps/{resolved.name}" + elif "setup.py" in files: + real_pkgs[resolved] = local_dep + if local_dep == ".": + working_dir = f"/deps/{resolved.name}" + else: + if any(file == "__init__.py" for file in files): + # flat layout + if "-" in resolved.name: + raise ValueError( + f"Package name '{resolved.name}' contains a hyphen. " + "Rename the directory to use it as flat-layout package." + ) + check_reserved(resolved.name, local_dep) + container_path = f"/deps/__outer_{resolved.name}/{resolved.name}" + else: + # src layout + container_path = f"/deps/__outer_{resolved.name}/src" + for file in files: + rfile = resolved / file + if ( + rfile.is_dir() + and file != "__pycache__" + and not file.startswith(".") + ): + try: + for subfile in os.listdir(rfile): + if subfile.endswith(".py"): + check_reserved(file, local_dep) + break + except PermissionError: + pass + faux_pkgs[resolved] = (local_dep, container_path) + if local_dep == ".": + working_dir = container_path + if "requirements.txt" in files: + rfile = resolved / "requirements.txt" + pip_reqs.append( + ( + rfile.relative_to(config_path.parent), + f"{container_path}/requirements.txt", + ) + ) + + return LocalDeps(pip_reqs, real_pkgs, faux_pkgs, working_dir) + + +def _update_graph_paths( + config_path: pathlib.Path, config: Config, local_deps: LocalDeps +) -> None: + for graph_id, import_str in config["graphs"].items(): + module_str, _, attr_str = import_str.partition(":") + if not module_str or not attr_str: + message = ( + 'Import string "{import_str}" must be in format ":".' + ) + raise ValueError(message.format(import_str=import_str)) + if "/" in module_str: + resolved = config_path.parent / module_str + if not resolved.exists(): + raise FileNotFoundError(f"Could not find local module: {resolved}") + elif not resolved.is_file(): + raise IsADirectoryError(f"Local module must be a file: {resolved}") + else: + for path in local_deps.real_pkgs: + if resolved.is_relative_to(path): + module_str = f"/deps/{path.name}/{resolved.relative_to(path)}" + break + else: + for faux_pkg, (_, destpath) in local_deps.faux_pkgs.items(): + if resolved.is_relative_to(faux_pkg): + module_str = f"{destpath}/{resolved.relative_to(faux_pkg)}" + break + else: + raise ValueError( + f"Module '{import_str}' not found in 'dependencies' list. " + "Add its containing package to 'dependencies' list." + ) + # update the config + config["graphs"][graph_id] = f"{module_str}:{attr_str}" + + +def config_to_docker(config_path: pathlib.Path, config: Config): + # configure pip + pip_install = "pip install -c /api/constraints.txt" + if config.get("pip_config_file"): + pip_install = f"PIP_CONFIG_FILE=/pipconfig.txt {pip_install}" + pip_config_file_str = ( + f"ADD {config['pip_config_file']} /pipconfig.txt" + if config.get("pip_config_file") + else "" + ) + + # collect dependencies + pypi_deps = [dep for dep in config["dependencies"] if not dep.startswith(".")] + local_deps = _assemble_local_deps(config_path, config) + + # rewrite graph paths + _update_graph_paths(config_path, config, local_deps) + + pip_pkgs_str = f"RUN {pip_install} {' '.join(pypi_deps)}" if pypi_deps else "" + if local_deps.pip_reqs: + pip_reqs_str = os.linesep.join( + f"ADD {reqpath} {destpath}" for reqpath, destpath in local_deps.pip_reqs + ) + pip_reqs_str += f'{os.linesep}RUN {pip_install} {" ".join("-r " + r for _,r in local_deps.pip_reqs)}' + + else: + pip_reqs_str = "" + + # https://setuptools.pypa.io/en/latest/userguide/datafiles.html#package-data + # https://til.simonwillison.net/python/pyproject + faux_pkgs_str = f"{os.linesep}{os.linesep}".join( + f"""ADD {relpath} {destpath} +COPY < Version: + parts = version.split(".", 2) + if len(parts) == 1: + major = parts[0] + minor = "0" + patch = "0" + elif len(parts) == 2: + major, minor = parts + patch = "0" + else: + major, minor, patch = parts + return Version(int(major.lstrip("v")), int(minor), int(patch.split("-")[0])) + + +def check_capabilities(runner) -> DockerCapabilities: + # check docker available + try: + stdout, _ = runner.run(subp_exec("docker", "info", "-f", "json", collect=True)) + info = json.loads(stdout) + except (click.exceptions.Exit, json.JSONDecodeError): + raise click.UsageError("Docker not installed or not running") from None + + compose_type: DockerComposeType + try: + compose = next( + p for p in info["ClientInfo"]["Plugins"] if p["Name"] == "compose" + ) + compose_type = "plugin" + except (KeyError, StopIteration): + if shutil.which("docker-compose") is None: + raise click.UsageError("Docker Compose not installed") from None + + compose_type = "standalone" + + # parse versions + docker_version = _parse_version(info["ServerVersion"]) + compose_version = _parse_version(compose["Version"]) + + # check capabilities + return DockerCapabilities( + version_docker=docker_version, + version_compose=compose_version, + healthcheck_start_interval=docker_version >= Version(25, 0, 0), + compose_type=compose_type, + ) + + +def compose( + capabilities: DockerCapabilities, + *, + port: int, + debugger_port: Optional[int] = None, + # postgres://user:password@host:port/database?option=value + postgres_uri: Optional[str] = None, +) -> str: + if postgres_uri is None: + include_db = True + postgres_uri = DEFAULT_POSTGRES_URI + else: + include_db = False + + db = DB.format() if include_db else "" + volumes = ( + """volumes: + langgraph-data: + driver: local +""" + if include_db + else "" + ) + if db: + if capabilities.healthcheck_start_interval: + db += """ + interval: 60s + start_interval: 1s""" + else: + db += """ + interval: 5s""" + + compose_str = f"""{volumes}services: +{db} +{DEBUGGER.format(debugger_port=debugger_port) if debugger_port else ""} + langgraph-api: + restart: on-failure + ports: + - "{port}:8000" + depends_on: + langgraph-postgres: + condition: service_healthy + environment: + POSTGRES_URI: {postgres_uri} +""" + if capabilities.healthcheck_start_interval: + compose_str += """ healthcheck: + interval: 60s + start_interval: 1s + start_period: 10s""" + + return compose_str diff --git a/libs/cli/langgraph_cli/exec.py b/libs/cli/langgraph_cli/exec.py new file mode 100644 index 000000000..e165b9e86 --- /dev/null +++ b/libs/cli/langgraph_cli/exec.py @@ -0,0 +1,140 @@ +import asyncio +import os +import signal +import sys +from contextlib import contextmanager +from typing import Callable, Optional, cast + +import click.exceptions + + +@contextmanager +def Runner(): + if hasattr(asyncio, "Runner"): + with asyncio.Runner() as runner: + yield runner + else: + + class _Runner: + def __enter__(self): + return self + + def __exit__(self, *args): + pass + + def run(self, coro): + asyncio.run(coro) + + yield _Runner() + + +async def subp_exec( + cmd: str, + *args: str, + input: Optional[str] = None, + wait: Optional[float] = None, + verbose: bool = False, + collect: bool = False, + on_stdout: Optional[Callable[[str], Optional[bool]]] = None, +) -> tuple[Optional[str], Optional[str]]: + if verbose: + cmd_str = f"+ {cmd} {' '.join(map(str, args))}" + if input: + print(cmd_str, " <\n", "\n".join(filter(None, input.splitlines())), sep="") + else: + print(cmd_str) + if wait: + await asyncio.sleep(wait) + + try: + proc = await asyncio.create_subprocess_exec( + cmd, + *args, + stdin=asyncio.subprocess.PIPE if input else None, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + ) + + def signal_handler(): + # make sure process exists, then terminate it + if proc.returncode is None: + proc.terminate() + + loop = asyncio.get_event_loop() + loop.add_signal_handler(signal.SIGINT, signal_handler) + loop.add_signal_handler(signal.SIGTERM, signal_handler) + + empty_fut: asyncio.Future = asyncio.Future() + empty_fut.set_result(None) + stdout, stderr, _ = await asyncio.gather( + monitor_stream( + cast(asyncio.StreamReader, proc.stdout), + collect=True, + display=verbose, + on_line=on_stdout, + ), + monitor_stream( + cast(asyncio.StreamReader, proc.stderr), + collect=True, + display=verbose, + ), + proc._feed_stdin(input.encode()) if input else empty_fut, # type: ignore[attr-defined] + ) + returncode = await proc.wait() + if ( + returncode is not None + and returncode != 0 # success + and returncode != 130 # user interrupt + ): + sys.stdout.write(stdout.decode() if stdout else "") + sys.stderr.write(stderr.decode() if stderr else "") + raise click.exceptions.Exit(returncode) + if collect: + return ( + stdout.decode() if stdout else None, + stderr.decode() if stderr else None, + ) + else: + return None, None + finally: + try: + if proc.returncode is None: + try: + os.killpg(os.getpgid(proc.pid), signal.SIGINT) + except (ProcessLookupError, KeyboardInterrupt): + pass + + loop.remove_signal_handler(signal.SIGINT) + loop.remove_signal_handler(signal.SIGTERM) + except UnboundLocalError: + pass + + +async def monitor_stream( + stream: asyncio.StreamReader, + collect: bool = False, + display: bool = False, + on_line: Optional[Callable[[str], Optional[bool]]] = None, +) -> Optional[bytearray]: + if collect: + ba = bytearray() + + def handle(line: bytes): + nonlocal on_line + nonlocal display + + if collect: + ba.extend(line) + if display: + sys.stdout.write(line.decode()) + if on_line: + if on_line(line.decode()): + on_line = None + display = True + + async for line in stream: + await asyncio.to_thread(handle, line) + if collect: + return ba + else: + return None diff --git a/libs/cli/langgraph_cli/progress.py b/libs/cli/langgraph_cli/progress.py new file mode 100644 index 000000000..38154f1b9 --- /dev/null +++ b/libs/cli/langgraph_cli/progress.py @@ -0,0 +1,64 @@ +import sys +import threading +import time +from typing import Callable + + +class Progress: + delay: float = 0.1 + + @staticmethod + def spinning_cursor(): + while True: + yield from "|/-\\" + + def __init__(self, *, message=""): + self.message = message + self.spinner_generator = self.spinning_cursor() + + def spinner_iteration(self): + message = self.message + sys.stdout.write(next(self.spinner_generator) + " " + message) + sys.stdout.flush() + time.sleep(self.delay) + # clear the spinner and message + sys.stdout.write( + "\b" * (len(message) + 2) + + " " * (len(message) + 2) + + "\b" * (len(message) + 2) + ) + sys.stdout.flush() + + def spinner_task(self): + while self.message: + message = self.message + sys.stdout.write(next(self.spinner_generator) + " " + message) + sys.stdout.flush() + time.sleep(self.delay) + # clear the spinner and message + sys.stdout.write( + "\b" * (len(message) + 2) + + " " * (len(message) + 2) + + "\b" * (len(message) + 2) + ) + sys.stdout.flush() + + def __enter__(self) -> Callable[[str], None]: + self.thread = threading.Thread(target=self.spinner_task) + self.thread.start() + + def set_message(message): + self.message = message + if not message: + self.thread.join() + + return set_message + + def __exit__(self, exception, value, tb): + self.message = "" + try: + self.thread.join() + finally: + del self.thread + if exception is not None: + return False diff --git a/libs/cli/poetry.lock b/libs/cli/poetry.lock new file mode 100644 index 000000000..4f6c66396 --- /dev/null +++ b/libs/cli/poetry.lock @@ -0,0 +1,327 @@ +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +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 = "codespell" +version = "2.2.6" +description = "Codespell" +optional = false +python-versions = ">=3.8" +files = [ + {file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, + {file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, +] + +[package.extras] +dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] +hard-encoding-detection = ["chardet"] +toml = ["tomli"] +types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] + +[[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" +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 = "docopt" +version = "0.6.2" +description = "Pythonic argument parser, that will make you smile" +optional = false +python-versions = "*" +files = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.0-py3-none-any.whl", hash = "sha256:4bfd3996ac73b41e9b9628b04e079f193850720ea5945fc96a08633c66912f14"}, + {file = "exceptiongroup-1.2.0.tar.gz", hash = "sha256:91f5c769735f051a4290d52edd0858999b57e5876e9f85937691bd4c9fa3ed68"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "mypy" +version = "1.10.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, + {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, + {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, + {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "packaging" +version = "23.2" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, + {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, +] + +[[package]] +name = "pluggy" +version = "1.3.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, + {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "7.4.3" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.3-py3-none-any.whl", hash = "sha256:0d009c083ea859a71b76adf7c1d502e4bc170b80a8ef002da5806527b9591fac"}, + {file = "pytest-7.4.3.tar.gz", hash = "sha256:d989d136982de4e3b29dabcc838ad581c64e8ed52c11fbe86ddebd9da0818cd5"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.1" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-asyncio-0.21.1.tar.gz", hash = "sha256:40a7eae6dded22c7b604986855ea48400ab15b069ae38116e8c01238e9eeb64d"}, + {file = "pytest_asyncio-0.21.1-py3-none-any.whl", hash = "sha256:8666c1c8ac02631d7c51ba282e0c69a8a452b211ffedf2599099845da5c5c37b"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-mock" +version = "3.12.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.12.0.tar.gz", hash = "sha256:31a40f038c22cad32287bb43932054451ff5583ff094bca6f675df2f8bc1a6e9"}, + {file = "pytest_mock-3.12.0-py3-none-any.whl", hash = "sha256:0972719a7263072da3a21c7f4773069bcc7486027d7e8e1f81d98a47e701bc4f"}, +] + +[package.dependencies] +pytest = ">=5.0" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-watch" +version = "4.2.0" +description = "Local continuous test runner with pytest and watchdog." +optional = false +python-versions = "*" +files = [ + {file = "pytest-watch-4.2.0.tar.gz", hash = "sha256:06136f03d5b361718b8d0d234042f7b2f203910d8568f63df2f866b547b3d4b9"}, +] + +[package.dependencies] +colorama = ">=0.3.3" +docopt = ">=0.4.0" +pytest = ">=2.6.4" +watchdog = ">=0.6.0" + +[[package]] +name = "ruff" +version = "0.1.6" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:88b8cdf6abf98130991cbc9f6438f35f6e8d41a02622cc5ee130a02a0ed28703"}, + {file = "ruff-0.1.6-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:5c549ed437680b6105a1299d2cd30e4964211606eeb48a0ff7a93ef70b902248"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cf5f701062e294f2167e66d11b092bba7af6a057668ed618a9253e1e90cfd76"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:05991ee20d4ac4bb78385360c684e4b417edd971030ab12a4fbd075ff535050e"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:87455a0c1f739b3c069e2f4c43b66479a54dea0276dd5d4d67b091265f6fd1dc"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:683aa5bdda5a48cb8266fcde8eea2a6af4e5700a392c56ea5fb5f0d4bfdc0240"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:137852105586dcbf80c1717facb6781555c4e99f520c9c827bd414fac67ddfb6"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bd98138a98d48a1c36c394fd6b84cd943ac92a08278aa8ac8c0fdefcf7138f35"}, + {file = "ruff-0.1.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a0cd909d25f227ac5c36d4e7e681577275fb74ba3b11d288aff7ec47e3ae745"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e8fd1c62a47aa88a02707b5dd20c5ff20d035d634aa74826b42a1da77861b5ff"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:fd89b45d374935829134a082617954120d7a1470a9f0ec0e7f3ead983edc48cc"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_i686.whl", hash = "sha256:491262006e92f825b145cd1e52948073c56560243b55fb3b4ecb142f6f0e9543"}, + {file = "ruff-0.1.6-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:ea284789861b8b5ca9d5443591a92a397ac183d4351882ab52f6296b4fdd5462"}, + {file = "ruff-0.1.6-py3-none-win32.whl", hash = "sha256:1610e14750826dfc207ccbcdd7331b6bd285607d4181df9c1c6ae26646d6848a"}, + {file = "ruff-0.1.6-py3-none-win_amd64.whl", hash = "sha256:4558b3e178145491e9bc3b2ee3c4b42f19d19384eaa5c59d10acf6e8f8b57e33"}, + {file = "ruff-0.1.6-py3-none-win_arm64.whl", hash = "sha256:03910e81df0d8db0e30050725a5802441c2022ea3ae4fe0609b76081731accbc"}, + {file = "ruff-0.1.6.tar.gz", hash = "sha256:1b09f29b16c6ead5ea6b097ef2764b42372aebe363722f1605ecbcd2b9207184"}, +] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.12.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.12.0-py3-none-any.whl", hash = "sha256:b349c66bea9016ac22978d800cfff206d5f9816951f12a7d0ec5578b0a819594"}, + {file = "typing_extensions-4.12.0.tar.gz", hash = "sha256:8cbcdc8606ebcb0d95453ad7dc5065e6237b6aa230a31e81d0f440c30fed5fd8"}, +] + +[[package]] +name = "watchdog" +version = "3.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.7" +files = [ + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:336adfc6f5cc4e037d52db31194f7581ff744b67382eb6021c868322e32eef41"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:a70a8dcde91be523c35b2bf96196edc5730edb347e374c7de7cd20c43ed95397"}, + {file = "watchdog-3.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:adfdeab2da79ea2f76f87eb42a3ab1966a5313e5a69a0213a3cc06ef692b0e96"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:2b57a1e730af3156d13b7fdddfc23dea6487fceca29fc75c5a868beed29177ae"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ade88d0d778b1b222adebcc0927428f883db07017618a5e684fd03b83342bd9"}, + {file = "watchdog-3.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7e447d172af52ad204d19982739aa2346245cc5ba6f579d16dac4bfec226d2e7"}, + {file = "watchdog-3.0.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:9fac43a7466eb73e64a9940ac9ed6369baa39b3bf221ae23493a9ec4d0022674"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8ae9cda41fa114e28faf86cb137d751a17ffd0316d1c34ccf2235e8a84365c7f"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:25f70b4aa53bd743729c7475d7ec41093a580528b100e9a8c5b5efe8899592fc"}, + {file = "watchdog-3.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4f94069eb16657d2c6faada4624c39464f65c05606af50bb7902e036e3219be3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7c5f84b5194c24dd573fa6472685b2a27cc5a17fe5f7b6fd40345378ca6812e3"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:3aa7f6a12e831ddfe78cdd4f8996af9cf334fd6346531b16cec61c3b3c0d8da0"}, + {file = "watchdog-3.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:233b5817932685d39a7896b1090353fc8efc1ef99c9c054e46c8002561252fb8"}, + {file = "watchdog-3.0.0-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:13bbbb462ee42ec3c5723e1205be8ced776f05b100e4737518c67c8325cf6100"}, + {file = "watchdog-3.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:8f3ceecd20d71067c7fd4c9e832d4e22584318983cabc013dbf3f70ea95de346"}, + {file = "watchdog-3.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:c9d8c8ec7efb887333cf71e328e39cffbf771d8f8f95d308ea4125bf5f90ba64"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:0e06ab8858a76e1219e68c7573dfeba9dd1c0219476c5a44d5333b01d7e1743a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:d00e6be486affb5781468457b21a6cbe848c33ef43f9ea4a73b4882e5f188a44"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:c07253088265c363d1ddf4b3cdb808d59a0468ecd017770ed716991620b8f77a"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:5113334cf8cf0ac8cd45e1f8309a603291b614191c9add34d33075727a967709"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:51f90f73b4697bac9c9a78394c3acbbd331ccd3655c11be1a15ae6fe289a8c83"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:ba07e92756c97e3aca0912b5cbc4e5ad802f4557212788e72a72a47ff376950d"}, + {file = "watchdog-3.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:d429c2430c93b7903914e4db9a966c7f2b068dd2ebdd2fa9b9ce094c7d459f33"}, + {file = "watchdog-3.0.0-py3-none-win32.whl", hash = "sha256:3ed7c71a9dccfe838c2f0b6314ed0d9b22e77d268c67e015450a29036a81f60f"}, + {file = "watchdog-3.0.0-py3-none-win_amd64.whl", hash = "sha256:4c9956d27be0bb08fc5f30d9d0179a855436e655f046d288e2bcc11adfae893c"}, + {file = "watchdog-3.0.0-py3-none-win_ia64.whl", hash = "sha256:5d9f3a10e02d7371cd929b5d8f11e87d4bad890212ed3901f9b4d68767bee759"}, + {file = "watchdog-3.0.0.tar.gz", hash = "sha256:4d98a320595da7a7c5a18fc48cb633c2e73cda78f93cac2ef42d42bf609a33f9"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9.0,<4.0" +content-hash = "5efa2f1ed4bd611a45e5d43d7c3fb907a8fa4447e2d1c30ce26b830411e189dd" diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml new file mode 100644 index 000000000..dca1782cb --- /dev/null +++ b/libs/cli/pyproject.toml @@ -0,0 +1,53 @@ +[tool.poetry] +name = "langgraph-cli" +version = "0.1.35" +description = "CLI for interacting with LangGraph API" +authors = ["Nuno Campos "] +readme = "README.md" +packages = [{include = "langgraph_cli"}] + +[tool.poetry.scripts] +langgraph = "langgraph_cli.cli:cli" + +[tool.poetry.dependencies] +python = "^3.9.0,<4.0" +click = "^8.1.7" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.1.4" +codespell = "^2.2.0" +pytest = "^7.2.1" +pytest-asyncio = "^0.21.1" +pytest-mock = "^3.11.1" +pytest-watch = "^4.2.0" +mypy = "^1.10.0" + +[tool.pytest.ini_options] +# --strict-markers will raise errors on unknown marks. +# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks +# +# https://docs.pytest.org/en/7.1.x/reference/reference.html +# --strict-config any warnings encountered while parsing the `pytest` +# section of the configuration file raise errors. +addopts = "--strict-markers --strict-config --durations=5 -vv" +asyncio_mode = "auto" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +select = [ + # pycodestyle + "E", + # Pyflakes + "F", + # pyupgrade + "UP", + # flake8-bugbear + "B", + # isort + "I", +] +ignore = [ "E501", "B008" ] diff --git a/langgraph/serde/__init__.py b/libs/cli/tests/__init__.py similarity index 100% rename from langgraph/serde/__init__.py rename to libs/cli/tests/__init__.py diff --git a/tests/__init__.py b/libs/cli/tests/unit_tests/__init__.py similarity index 100% rename from tests/__init__.py rename to libs/cli/tests/unit_tests/__init__.py diff --git a/langgraph/py.typed b/libs/cli/tests/unit_tests/agent.py similarity index 100% rename from langgraph/py.typed rename to libs/cli/tests/unit_tests/agent.py diff --git a/tests/checkpoint/__init__.py b/libs/cli/tests/unit_tests/graphs/agent.py similarity index 100% rename from tests/checkpoint/__init__.py rename to libs/cli/tests/unit_tests/graphs/agent.py diff --git a/libs/cli/tests/unit_tests/helpers.py b/libs/cli/tests/unit_tests/helpers.py new file mode 100644 index 000000000..79b67a2c9 --- /dev/null +++ b/libs/cli/tests/unit_tests/helpers.py @@ -0,0 +1,2 @@ +def clean_empty_lines(input_str: str): + return "\n".join(filter(None, input_str.splitlines())) diff --git a/libs/cli/tests/unit_tests/test_cli.py b/libs/cli/tests/unit_tests/test_cli.py new file mode 100644 index 000000000..44f63bb2a --- /dev/null +++ b/libs/cli/tests/unit_tests/test_cli.py @@ -0,0 +1,113 @@ +import pathlib + +from langgraph_cli.cli import prepare_args_and_stdin +from langgraph_cli.config import Config, validate_config +from langgraph_cli.docker import DEFAULT_POSTGRES_URI, DockerCapabilities, Version + +from .helpers import clean_empty_lines + +DEFAULT_DOCKER_CAPABILITIES = DockerCapabilities( + version_docker=Version(26, 1, 1), + version_compose=Version(2, 27, 0), + healthcheck_start_interval=True, +) + + +def test_prepare_args_and_stdin(): + # this basically serves as an end-to-end test for using config and docker helpers + config_path = pathlib.Path("./langgraph.json") + config = validate_config( + Config(dependencies=["."], graphs={"agent": "agent.py:graph"}) + ) + port = 8000 + debugger_port = 8001 + + actual_args, actual_stdin = prepare_args_and_stdin( + capabilities=DEFAULT_DOCKER_CAPABILITIES, + config_path=config_path, + config=config, + docker_compose="custom-docker-compose.yml", + port=port, + debugger_port=debugger_port, + watch=True, + langgraph_api_path="path/to/langgraph-api", + ) + + expected_args = [ + "--project-directory", + ".", + "-f", + "custom-docker-compose.yml", + "-f", + "-", + ] + expected_stdin = f"""volumes: + langgraph-data: + driver: local +services: + langgraph-postgres: + image: postgres:16 + restart: on-failure + ports: + - "5433:5432" + environment: + POSTGRES_DB: postgres + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + volumes: + - langgraph-data:/var/lib/postgresql/data + healthcheck: + test: pg_isready -U postgres + start_period: 10s + timeout: 1s + retries: 5 + interval: 60s + start_interval: 1s + langgraph-debugger: + image: langchain/langgraph-debugger + restart: on-failure + ports: + - "{debugger_port}:80" + depends_on: + langgraph-postgres: + condition: service_healthy + langgraph-api: + restart: on-failure + ports: + - "8000:8000" + depends_on: + langgraph-postgres: + condition: service_healthy + environment: + POSTGRES_URI: {DEFAULT_POSTGRES_URI} + healthcheck: + interval: 60s + start_interval: 1s + start_period: 10s + + pull_policy: build + build: + context: . + dockerfile_inline: | + FROM langchain/langgraph-api:3.11 + ADD . /deps/ + RUN pip install -c /api/constraints.txt -e /deps/* + ENV LANGSERVE_GRAPHS='{{"agent": "agent.py:graph"}}' + WORKDIR /deps/ + + develop: + watch: + - path: langgraph.json + action: rebuild + ignore: + - .langgraph-data + - path: . + action: rebuild + ignore: + - .langgraph-data + - path: path/to/langgraph-api + action: sync+restart + target: /api/langgraph_api\ +""" + assert actual_args == expected_args + assert clean_empty_lines(actual_stdin) == expected_stdin diff --git a/libs/cli/tests/unit_tests/test_config.json b/libs/cli/tests/unit_tests/test_config.json new file mode 100644 index 000000000..b75d747c4 --- /dev/null +++ b/libs/cli/tests/unit_tests/test_config.json @@ -0,0 +1,13 @@ +{ + "python_version": "3.12", + "pip_config_file": "pipconfig.txt", + "dockerfile_lines": ["ARG meow"], + "dependencies": [ + "langchain_openai", + "." + ], + "graphs": { + "agent": "tests/unit_tests/agent.py:graph" + }, + "env": ".env" +} \ No newline at end of file diff --git a/libs/cli/tests/unit_tests/test_config.py b/libs/cli/tests/unit_tests/test_config.py new file mode 100644 index 000000000..9adcbd071 --- /dev/null +++ b/libs/cli/tests/unit_tests/test_config.py @@ -0,0 +1,396 @@ +import os +import pathlib + +import click +import pytest + +from langgraph_cli.config import config_to_compose, config_to_docker, validate_config + +from .helpers import clean_empty_lines + +PATH_TO_CONFIG = pathlib.Path("tests/unit_tests/test_config.json") + + +def test_validate_config(): + # minimal config + expected_config = { + "dependencies": ["."], + "graphs": { + "agent": "./agent.py:graph", + }, + } + expected_config = { + "python_version": "3.11", + "pip_config_file": None, + "dockerfile_lines": [], + "env": {}, + **expected_config, + } + actual_config = validate_config(expected_config) + assert actual_config == expected_config + + # full config + env = ".env" + expected_config = { + "python_version": "3.12", + "pip_config_file": "pipconfig.txt", + "dockerfile_lines": ["ARG meow"], + "dependencies": [".", "langchain"], + "graphs": { + "agent": "./agent.py:graph", + }, + "env": env, + } + actual_config = validate_config(expected_config) + assert actual_config == expected_config + + # check wrong python version raises + with pytest.raises(click.UsageError): + validate_config( + { + "python_version": "3.9", + } + ) + + # check missing dependencies key raises + with pytest.raises(click.UsageError): + validate_config( + {"python_version": "3.9", "graphs": {"agent": "./agent.py:graph"}}, + ) + + # check missing graphs key raises + with pytest.raises(click.UsageError): + validate_config({"python_version": "3.9", "dependencies": ["."]}) + + +# config_to_docker +def test_config_to_docker_simple(): + graphs = {"agent": "./agent.py:graph"} + actual_docker_stdin = config_to_docker( + PATH_TO_CONFIG, validate_config({"dependencies": ["."], "graphs": graphs}) + ) + expected_docker_stdin = """\ +FROM langchain/langgraph-api:3.11 +ADD . /deps/__outer_unit_tests/unit_tests +COPY < - run all tests in file' + @echo 'test_watch - run unit tests in watch mode' diff --git a/langgraph/__init__.py b/libs/langgraph/langgraph/__init__.py similarity index 100% rename from langgraph/__init__.py rename to libs/langgraph/langgraph/__init__.py diff --git a/libs/langgraph/langgraph/_api/__init__.py b/libs/langgraph/langgraph/_api/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/langgraph/_api/deprecation.py b/libs/langgraph/langgraph/_api/deprecation.py similarity index 100% rename from langgraph/_api/deprecation.py rename to libs/langgraph/langgraph/_api/deprecation.py diff --git a/langgraph/channels/__init__.py b/libs/langgraph/langgraph/channels/__init__.py similarity index 100% rename from langgraph/channels/__init__.py rename to libs/langgraph/langgraph/channels/__init__.py diff --git a/langgraph/channels/any_value.py b/libs/langgraph/langgraph/channels/any_value.py similarity index 100% rename from langgraph/channels/any_value.py rename to libs/langgraph/langgraph/channels/any_value.py diff --git a/langgraph/channels/base.py b/libs/langgraph/langgraph/channels/base.py similarity index 100% rename from langgraph/channels/base.py rename to libs/langgraph/langgraph/channels/base.py diff --git a/langgraph/channels/binop.py b/libs/langgraph/langgraph/channels/binop.py similarity index 100% rename from langgraph/channels/binop.py rename to libs/langgraph/langgraph/channels/binop.py diff --git a/langgraph/channels/context.py b/libs/langgraph/langgraph/channels/context.py similarity index 100% rename from langgraph/channels/context.py rename to libs/langgraph/langgraph/channels/context.py diff --git a/langgraph/channels/dynamic_barrier_value.py b/libs/langgraph/langgraph/channels/dynamic_barrier_value.py similarity index 100% rename from langgraph/channels/dynamic_barrier_value.py rename to libs/langgraph/langgraph/channels/dynamic_barrier_value.py diff --git a/langgraph/channels/ephemeral_value.py b/libs/langgraph/langgraph/channels/ephemeral_value.py similarity index 100% rename from langgraph/channels/ephemeral_value.py rename to libs/langgraph/langgraph/channels/ephemeral_value.py diff --git a/langgraph/channels/last_value.py b/libs/langgraph/langgraph/channels/last_value.py similarity index 100% rename from langgraph/channels/last_value.py rename to libs/langgraph/langgraph/channels/last_value.py diff --git a/langgraph/channels/manager.py b/libs/langgraph/langgraph/channels/manager.py similarity index 100% rename from langgraph/channels/manager.py rename to libs/langgraph/langgraph/channels/manager.py diff --git a/langgraph/channels/named_barrier_value.py b/libs/langgraph/langgraph/channels/named_barrier_value.py similarity index 100% rename from langgraph/channels/named_barrier_value.py rename to libs/langgraph/langgraph/channels/named_barrier_value.py diff --git a/langgraph/channels/topic.py b/libs/langgraph/langgraph/channels/topic.py similarity index 100% rename from langgraph/channels/topic.py rename to libs/langgraph/langgraph/channels/topic.py diff --git a/langgraph/checkpoint/__init__.py b/libs/langgraph/langgraph/checkpoint/__init__.py similarity index 100% rename from langgraph/checkpoint/__init__.py rename to libs/langgraph/langgraph/checkpoint/__init__.py diff --git a/langgraph/checkpoint/aiosqlite.py b/libs/langgraph/langgraph/checkpoint/aiosqlite.py similarity index 100% rename from langgraph/checkpoint/aiosqlite.py rename to libs/langgraph/langgraph/checkpoint/aiosqlite.py diff --git a/langgraph/checkpoint/base.py b/libs/langgraph/langgraph/checkpoint/base.py similarity index 100% rename from langgraph/checkpoint/base.py rename to libs/langgraph/langgraph/checkpoint/base.py diff --git a/langgraph/checkpoint/id.py b/libs/langgraph/langgraph/checkpoint/id.py similarity index 100% rename from langgraph/checkpoint/id.py rename to libs/langgraph/langgraph/checkpoint/id.py diff --git a/langgraph/checkpoint/memory.py b/libs/langgraph/langgraph/checkpoint/memory.py similarity index 100% rename from langgraph/checkpoint/memory.py rename to libs/langgraph/langgraph/checkpoint/memory.py diff --git a/langgraph/checkpoint/sqlite.py b/libs/langgraph/langgraph/checkpoint/sqlite.py similarity index 100% rename from langgraph/checkpoint/sqlite.py rename to libs/langgraph/langgraph/checkpoint/sqlite.py diff --git a/langgraph/constants.py b/libs/langgraph/langgraph/constants.py similarity index 100% rename from langgraph/constants.py rename to libs/langgraph/langgraph/constants.py diff --git a/langgraph/errors.py b/libs/langgraph/langgraph/errors.py similarity index 100% rename from langgraph/errors.py rename to libs/langgraph/langgraph/errors.py diff --git a/langgraph/graph/__init__.py b/libs/langgraph/langgraph/graph/__init__.py similarity index 100% rename from langgraph/graph/__init__.py rename to libs/langgraph/langgraph/graph/__init__.py diff --git a/langgraph/graph/graph.py b/libs/langgraph/langgraph/graph/graph.py similarity index 100% rename from langgraph/graph/graph.py rename to libs/langgraph/langgraph/graph/graph.py diff --git a/langgraph/graph/message.py b/libs/langgraph/langgraph/graph/message.py similarity index 100% rename from langgraph/graph/message.py rename to libs/langgraph/langgraph/graph/message.py diff --git a/langgraph/graph/state.py b/libs/langgraph/langgraph/graph/state.py similarity index 100% rename from langgraph/graph/state.py rename to libs/langgraph/langgraph/graph/state.py diff --git a/langgraph/managed/__init__.py b/libs/langgraph/langgraph/managed/__init__.py similarity index 100% rename from langgraph/managed/__init__.py rename to libs/langgraph/langgraph/managed/__init__.py diff --git a/langgraph/managed/base.py b/libs/langgraph/langgraph/managed/base.py similarity index 100% rename from langgraph/managed/base.py rename to libs/langgraph/langgraph/managed/base.py diff --git a/langgraph/managed/few_shot.py b/libs/langgraph/langgraph/managed/few_shot.py similarity index 100% rename from langgraph/managed/few_shot.py rename to libs/langgraph/langgraph/managed/few_shot.py diff --git a/langgraph/managed/is_last_step.py b/libs/langgraph/langgraph/managed/is_last_step.py similarity index 100% rename from langgraph/managed/is_last_step.py rename to libs/langgraph/langgraph/managed/is_last_step.py diff --git a/langgraph/prebuilt/__init__.py b/libs/langgraph/langgraph/prebuilt/__init__.py similarity index 100% rename from langgraph/prebuilt/__init__.py rename to libs/langgraph/langgraph/prebuilt/__init__.py diff --git a/langgraph/prebuilt/agent_executor.py b/libs/langgraph/langgraph/prebuilt/agent_executor.py similarity index 100% rename from langgraph/prebuilt/agent_executor.py rename to libs/langgraph/langgraph/prebuilt/agent_executor.py diff --git a/langgraph/prebuilt/chat_agent_executor.py b/libs/langgraph/langgraph/prebuilt/chat_agent_executor.py similarity index 100% rename from langgraph/prebuilt/chat_agent_executor.py rename to libs/langgraph/langgraph/prebuilt/chat_agent_executor.py diff --git a/langgraph/prebuilt/tool_executor.py b/libs/langgraph/langgraph/prebuilt/tool_executor.py similarity index 100% rename from langgraph/prebuilt/tool_executor.py rename to libs/langgraph/langgraph/prebuilt/tool_executor.py diff --git a/langgraph/prebuilt/tool_node.py b/libs/langgraph/langgraph/prebuilt/tool_node.py similarity index 100% rename from langgraph/prebuilt/tool_node.py rename to libs/langgraph/langgraph/prebuilt/tool_node.py diff --git a/langgraph/prebuilt/tool_validator.py b/libs/langgraph/langgraph/prebuilt/tool_validator.py similarity index 100% rename from langgraph/prebuilt/tool_validator.py rename to libs/langgraph/langgraph/prebuilt/tool_validator.py diff --git a/langgraph/pregel/__init__.py b/libs/langgraph/langgraph/pregel/__init__.py similarity index 100% rename from langgraph/pregel/__init__.py rename to libs/langgraph/langgraph/pregel/__init__.py diff --git a/langgraph/pregel/debug.py b/libs/langgraph/langgraph/pregel/debug.py similarity index 100% rename from langgraph/pregel/debug.py rename to libs/langgraph/langgraph/pregel/debug.py diff --git a/langgraph/pregel/io.py b/libs/langgraph/langgraph/pregel/io.py similarity index 100% rename from langgraph/pregel/io.py rename to libs/langgraph/langgraph/pregel/io.py diff --git a/langgraph/pregel/log.py b/libs/langgraph/langgraph/pregel/log.py similarity index 100% rename from langgraph/pregel/log.py rename to libs/langgraph/langgraph/pregel/log.py diff --git a/langgraph/pregel/read.py b/libs/langgraph/langgraph/pregel/read.py similarity index 100% rename from langgraph/pregel/read.py rename to libs/langgraph/langgraph/pregel/read.py diff --git a/langgraph/pregel/retry.py b/libs/langgraph/langgraph/pregel/retry.py similarity index 100% rename from langgraph/pregel/retry.py rename to libs/langgraph/langgraph/pregel/retry.py diff --git a/langgraph/pregel/types.py b/libs/langgraph/langgraph/pregel/types.py similarity index 100% rename from langgraph/pregel/types.py rename to libs/langgraph/langgraph/pregel/types.py diff --git a/langgraph/pregel/validate.py b/libs/langgraph/langgraph/pregel/validate.py similarity index 100% rename from langgraph/pregel/validate.py rename to libs/langgraph/langgraph/pregel/validate.py diff --git a/langgraph/pregel/write.py b/libs/langgraph/langgraph/pregel/write.py similarity index 100% rename from langgraph/pregel/write.py rename to libs/langgraph/langgraph/pregel/write.py diff --git a/libs/langgraph/langgraph/py.typed b/libs/langgraph/langgraph/py.typed new file mode 100644 index 000000000..e69de29bb diff --git a/libs/langgraph/langgraph/serde/__init__.py b/libs/langgraph/langgraph/serde/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/langgraph/serde/base.py b/libs/langgraph/langgraph/serde/base.py similarity index 100% rename from langgraph/serde/base.py rename to libs/langgraph/langgraph/serde/base.py diff --git a/langgraph/serde/jsonplus.py b/libs/langgraph/langgraph/serde/jsonplus.py similarity index 100% rename from langgraph/serde/jsonplus.py rename to libs/langgraph/langgraph/serde/jsonplus.py diff --git a/langgraph/utils.py b/libs/langgraph/langgraph/utils.py similarity index 100% rename from langgraph/utils.py rename to libs/langgraph/langgraph/utils.py diff --git a/langgraph/version.py b/libs/langgraph/langgraph/version.py similarity index 100% rename from langgraph/version.py rename to libs/langgraph/langgraph/version.py diff --git a/poetry.lock b/libs/langgraph/poetry.lock similarity index 100% rename from poetry.lock rename to libs/langgraph/poetry.lock diff --git a/poetry.toml b/libs/langgraph/poetry.toml similarity index 100% rename from poetry.toml rename to libs/langgraph/poetry.toml diff --git a/pyproject.toml b/libs/langgraph/pyproject.toml similarity index 100% rename from pyproject.toml rename to libs/langgraph/pyproject.toml diff --git a/libs/langgraph/tests/__init__.py b/libs/langgraph/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/__snapshots__/test_pregel.ambr b/libs/langgraph/tests/__snapshots__/test_pregel.ambr similarity index 100% rename from tests/__snapshots__/test_pregel.ambr rename to libs/langgraph/tests/__snapshots__/test_pregel.ambr diff --git a/tests/__snapshots__/test_pregel_async.ambr b/libs/langgraph/tests/__snapshots__/test_pregel_async.ambr similarity index 100% rename from tests/__snapshots__/test_pregel_async.ambr rename to libs/langgraph/tests/__snapshots__/test_pregel_async.ambr diff --git a/tests/any_str.py b/libs/langgraph/tests/any_str.py similarity index 100% rename from tests/any_str.py rename to libs/langgraph/tests/any_str.py diff --git a/libs/langgraph/tests/checkpoint/__init__.py b/libs/langgraph/tests/checkpoint/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/tests/checkpoint/test_aiosqlite.py b/libs/langgraph/tests/checkpoint/test_aiosqlite.py similarity index 100% rename from tests/checkpoint/test_aiosqlite.py rename to libs/langgraph/tests/checkpoint/test_aiosqlite.py diff --git a/tests/checkpoint/test_memory.py b/libs/langgraph/tests/checkpoint/test_memory.py similarity index 100% rename from tests/checkpoint/test_memory.py rename to libs/langgraph/tests/checkpoint/test_memory.py diff --git a/tests/checkpoint/test_sqlite.py b/libs/langgraph/tests/checkpoint/test_sqlite.py similarity index 100% rename from tests/checkpoint/test_sqlite.py rename to libs/langgraph/tests/checkpoint/test_sqlite.py diff --git a/tests/conftest.py b/libs/langgraph/tests/conftest.py similarity index 100% rename from tests/conftest.py rename to libs/langgraph/tests/conftest.py diff --git a/tests/memory_assert.py b/libs/langgraph/tests/memory_assert.py similarity index 100% rename from tests/memory_assert.py rename to libs/langgraph/tests/memory_assert.py diff --git a/tests/test_channels.py b/libs/langgraph/tests/test_channels.py similarity index 100% rename from tests/test_channels.py rename to libs/langgraph/tests/test_channels.py diff --git a/tests/test_io.py b/libs/langgraph/tests/test_io.py similarity index 100% rename from tests/test_io.py rename to libs/langgraph/tests/test_io.py diff --git a/tests/test_jsonplus.py b/libs/langgraph/tests/test_jsonplus.py similarity index 100% rename from tests/test_jsonplus.py rename to libs/langgraph/tests/test_jsonplus.py diff --git a/tests/test_prebuilt.py b/libs/langgraph/tests/test_prebuilt.py similarity index 100% rename from tests/test_prebuilt.py rename to libs/langgraph/tests/test_prebuilt.py diff --git a/tests/test_pregel.py b/libs/langgraph/tests/test_pregel.py similarity index 100% rename from tests/test_pregel.py rename to libs/langgraph/tests/test_pregel.py diff --git a/tests/test_pregel_async.py b/libs/langgraph/tests/test_pregel_async.py similarity index 100% rename from tests/test_pregel_async.py rename to libs/langgraph/tests/test_pregel_async.py diff --git a/tests/test_state.py b/libs/langgraph/tests/test_state.py similarity index 100% rename from tests/test_state.py rename to libs/langgraph/tests/test_state.py diff --git a/tests/test_utils.py b/libs/langgraph/tests/test_utils.py similarity index 100% rename from tests/test_utils.py rename to libs/langgraph/tests/test_utils.py diff --git a/libs/sdk-js/LICENSE b/libs/sdk-js/LICENSE new file mode 100644 index 000000000..fc0602fee --- /dev/null +++ b/libs/sdk-js/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/sdk-js/client.cjs b/libs/sdk-js/client.cjs new file mode 100644 index 000000000..680e5bd38 --- /dev/null +++ b/libs/sdk-js/client.cjs @@ -0,0 +1 @@ +module.exports = require('./dist/client.cjs'); \ No newline at end of file diff --git a/libs/sdk-js/client.d.cts b/libs/sdk-js/client.d.cts new file mode 100644 index 000000000..c90177f3b --- /dev/null +++ b/libs/sdk-js/client.d.cts @@ -0,0 +1 @@ +export * from './dist/client.cjs' \ No newline at end of file diff --git a/libs/sdk-js/client.d.ts b/libs/sdk-js/client.d.ts new file mode 100644 index 000000000..ca6f7c421 --- /dev/null +++ b/libs/sdk-js/client.d.ts @@ -0,0 +1 @@ +export * from './dist/client.mjs' \ No newline at end of file diff --git a/libs/sdk-js/client.js b/libs/sdk-js/client.js new file mode 100644 index 000000000..ca6f7c421 --- /dev/null +++ b/libs/sdk-js/client.js @@ -0,0 +1 @@ +export * from './dist/client.mjs' \ No newline at end of file diff --git a/libs/sdk-js/index.cjs b/libs/sdk-js/index.cjs new file mode 100644 index 000000000..c84256f7a --- /dev/null +++ b/libs/sdk-js/index.cjs @@ -0,0 +1 @@ +module.exports = require('./dist/index.cjs'); \ No newline at end of file diff --git a/libs/sdk-js/index.d.cts b/libs/sdk-js/index.d.cts new file mode 100644 index 000000000..4adf1c804 --- /dev/null +++ b/libs/sdk-js/index.d.cts @@ -0,0 +1 @@ +export * from './dist/index.cjs' \ No newline at end of file diff --git a/libs/sdk-js/index.d.ts b/libs/sdk-js/index.d.ts new file mode 100644 index 000000000..307cab014 --- /dev/null +++ b/libs/sdk-js/index.d.ts @@ -0,0 +1 @@ +export * from './dist/index.mjs' \ No newline at end of file diff --git a/libs/sdk-js/index.js b/libs/sdk-js/index.js new file mode 100644 index 000000000..307cab014 --- /dev/null +++ b/libs/sdk-js/index.js @@ -0,0 +1 @@ +export * from './dist/index.mjs' \ No newline at end of file diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json new file mode 100644 index 000000000..fd7ee23e3 --- /dev/null +++ b/libs/sdk-js/package.json @@ -0,0 +1,64 @@ +{ + "name": "@langchain/langgraph-sdk", + "version": "0.0.1-rc.11", + "description": "Client library for interacting with the LangGraph API", + "type": "module", + "packageManager": "yarn@1.22.19", + "scripts": { + "clean": "rm -rf dist/ && node scripts/create-entrypoints.js clean", + "build": "yarn clean && yarn build:esm && yarn build:cjs && node scripts/create-entrypoints.js", + "build:esm": "rm -f src/package.json && tsc --outDir dist/ && rm -rf dist/tests dist/**/tests", + "build:cjs": "echo '{}' > src/package.json && tsc --outDir dist-cjs/ -p tsconfig.cjs.json && node scripts/move-cjs-to-dist.js && rm -r dist-cjs src/package.json", + "prepublish": "yarn run build", + "format": "prettier --write src", + "lint": "prettier --check src && tsc --noEmit" + }, + "main": "index.js", + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.15", + "eventsource-parser": "^1.1.2", + "p-queue": "^6.6.2", + "p-retry": "4", + "uuid": "^9.0.0" + }, + "devDependencies": { + "@tsconfig/recommended": "^1.0.2", + "@types/node": "^20.12.12", + "@types/uuid": "^9.0.1", + "prettier": "^3.2.5", + "typescript": "^5.4.5" + }, + "exports": { + ".": { + "types": { + "import": "./index.d.ts", + "require": "./index.d.cts", + "default": "./index.d.ts" + }, + "import": "./index.js", + "require": "./index.cjs" + }, + "./client": { + "types": { + "import": "./client.d.ts", + "require": "./client.d.cts", + "default": "./client.d.ts" + }, + "import": "./client.js", + "require": "./client.cjs" + }, + "./package.json": "./package.json" + }, + "files": [ + "dist/", + "client.cjs", + "client.js", + "client.d.ts", + "client.d.cts", + "index.cjs", + "index.js", + "index.d.ts", + "index.d.cts" + ] +} diff --git a/libs/sdk-js/scripts/create-entrypoints.js b/libs/sdk-js/scripts/create-entrypoints.js new file mode 100644 index 000000000..da14512f9 --- /dev/null +++ b/libs/sdk-js/scripts/create-entrypoints.js @@ -0,0 +1,115 @@ +import * as fs from "fs"; +import * as path from "path"; + +// This lists all the entrypoints for the library. Each key corresponds to an +// importable path, eg. `import { Foo } from "langgraph-sdk/client"`. +// The value is the path to the file in `src/` that exports the entrypoint. +// This is used to generate the `exports` field in package.json. +// Order is not important. +const entrypoints = { client: "client" }; + +const updateJsonFile = (relativePath, updateFunction) => { + const contents = fs.readFileSync(relativePath).toString(); + const res = updateFunction(JSON.parse(contents)); + fs.writeFileSync(relativePath, JSON.stringify(res, null, 2) + "\n"); +}; + +const generateFiles = () => { + const files = [...Object.entries(entrypoints), ["index", "index"]].flatMap( + ([key, value]) => { + const nrOfDots = key.split("/").length - 1; + const relativePath = "../".repeat(nrOfDots) || "./"; + const compiledPath = `${relativePath}dist/${value}`; + return [ + [`${key}.cjs`, `module.exports = require('${compiledPath}.cjs');`], + [`${key}.js`, `export * from '${compiledPath}.mjs'`], + [`${key}.d.ts`, `export * from '${compiledPath}.mjs'`], + [`${key}.d.cts`, `export * from '${compiledPath}.cjs'`], + ]; + }, + ); + + return Object.fromEntries(files); +}; + +const updateConfig = () => { + // Update tsconfig.json `typedocOptions.entryPoints` field + updateJsonFile("./tsconfig.json", (json) => ({ + ...json, + typedocOptions: { + ...json.typedocOptions, + entryPoints: [...Object.keys(entrypoints)].map( + (key) => `src/${entrypoints[key]}.ts`, + ), + }, + })); + + const generatedFiles = generateFiles(); + const filenames = Object.keys(generatedFiles); + + // Update package.json `exports` and `files` fields + updateJsonFile("./package.json", (json) => ({ + ...json, + exports: Object.assign( + Object.fromEntries( + ["index", ...Object.keys(entrypoints)].map((key) => { + let entryPoint = { + types: { + import: `./${key}.d.ts`, + require: `./${key}.d.cts`, + default: `./${key}.d.ts`, + }, + import: `./${key}.js`, + require: `./${key}.cjs`, + }; + + return [key === "index" ? "." : `./${key}`, entryPoint]; + }), + ), + { + "./package.json": "./package.json", + }, + ), + files: ["dist/", ...filenames], + })); + + // Write generated files + Object.entries(generatedFiles).forEach(([filename, content]) => { + fs.mkdirSync(path.dirname(filename), { + recursive: true, + }); + fs.writeFileSync(filename, content); + }); + + const gitignore = fs.readFileSync("./.gitignore").toString(); + const lines = gitignore.split("\n"); + const startMarker = "## GENERATED create-entrypoints.js"; + const endMarker = "## END GENERATED create-entrypoints.js"; + const startIdx = lines.findIndex((line) => line.includes(startMarker)); + const endIdx = lines.findIndex((line) => line.includes(endMarker)); + const newLines = [ + ...lines.slice(0, startIdx + 1), + ...filenames.map((fname) => `/${fname}`), + ...lines.slice(endIdx), + ]; + fs.writeFileSync("./.gitignore", newLines.join("\n")); +}; + +const cleanGenerated = () => { + const filenames = Object.keys(generateFiles()); + filenames.forEach((fname) => { + try { + fs.unlinkSync(fname); + } catch { + // ignore error + } + }); +}; + +const command = process.argv[2]; + +if (command === "clean") { + cleanGenerated(); +} else { + updateConfig(); +} diff --git a/libs/sdk-js/scripts/move-cjs-to-dist.js b/libs/sdk-js/scripts/move-cjs-to-dist.js new file mode 100644 index 000000000..1e89ccca8 --- /dev/null +++ b/libs/sdk-js/scripts/move-cjs-to-dist.js @@ -0,0 +1,38 @@ +import { resolve, dirname, parse, format } from "node:path"; +import { readdir, readFile, writeFile } from "node:fs/promises"; +import { fileURLToPath } from "node:url"; + +function abs(relativePath) { + return resolve(dirname(fileURLToPath(import.meta.url)), relativePath); +} + +async function moveAndRename(source, dest) { + for (const file of await readdir(abs(source), { withFileTypes: true })) { + if (file.isDirectory()) { + await moveAndRename(`${source}/${file.name}`, `${dest}/${file.name}`); + } else if (file.isFile()) { + const parsed = parse(file.name); + + // Ignore anything that's not a .js file + if (parsed.ext !== ".js") { + continue; + } + + // Rewrite any require statements to use .cjs + const content = await readFile(abs(`${source}/${file.name}`), "utf8"); + const rewritten = content.replace(/require\("(\..+?).js"\)/g, (_, p1) => { + return `require("${p1}.cjs")`; + }); + + // Rename the file to .cjs + const renamed = format({ name: parsed.name, ext: ".cjs" }); + + await writeFile(abs(`${dest}/${renamed}`), rewritten, "utf8"); + } + } +} + +moveAndRename("../dist-cjs", "../dist").catch((err) => { + console.error(err); + process.exit(1); +}); diff --git a/libs/sdk-js/src/client.mts b/libs/sdk-js/src/client.mts new file mode 100644 index 000000000..3311daba5 --- /dev/null +++ b/libs/sdk-js/src/client.mts @@ -0,0 +1,713 @@ +import { + Assistant, + AssistantGraph, + Config, + DefaultValues, + GraphSchema, + Metadata, + Run, + RunEvent, + Thread, + ThreadState, +} from "./schema.js"; +import { AsyncCaller, AsyncCallerParams } from "./utils/async_caller.mjs"; +import { EventSourceParser, createParser } from "eventsource-parser"; +import { IterableReadableStream } from "./utils/stream.mjs"; +import { + RunsCreatePayload, + RunsStreamPayload, + RunsWaitPayload, + StreamEvent, +} from "./types.mjs"; + +interface ClientConfig { + apiUrl?: string; + callerOptions?: AsyncCallerParams; + timeoutMs?: number; + defaultHeaders?: Record; +} + +class BaseClient { + protected asyncCaller: AsyncCaller; + + protected timeoutMs: number; + + protected apiUrl: string; + + protected defaultHeaders: Record; + + constructor(config?: ClientConfig) { + this.asyncCaller = new AsyncCaller({ + maxRetries: 4, + maxConcurrency: 4, + ...config?.callerOptions, + }); + + this.timeoutMs = config?.timeoutMs || 12_000; + this.apiUrl = config?.apiUrl || "http://localhost:8123"; + this.defaultHeaders = config?.defaultHeaders || {}; + } + + protected prepareFetchOptions( + path: string, + options?: RequestInit & { + json?: unknown; + params?: Record; + }, + ): [url: URL, init: RequestInit] { + const mutatedOptions = { + ...options, + headers: { ...this.defaultHeaders, ...options?.headers }, + }; + + if (mutatedOptions.json) { + mutatedOptions.body = JSON.stringify(mutatedOptions.json); + mutatedOptions.headers = { + ...mutatedOptions.headers, + "Content-Type": "application/json", + }; + delete mutatedOptions.json; + } + + const targetUrl = new URL(`${this.apiUrl}${path}`); + + if (mutatedOptions.params) { + for (const [key, value] of Object.entries(mutatedOptions.params)) { + if (value == null) continue; + + let strValue = + typeof value === "string" || typeof value === "number" + ? value.toString() + : JSON.stringify(value); + + targetUrl.searchParams.append(key, strValue); + } + delete mutatedOptions.params; + } + + return [targetUrl, mutatedOptions]; + } + + protected async fetch( + path: string, + options?: RequestInit & { + json?: unknown; + params?: Record; + }, + ): Promise { + const response = await this.asyncCaller.fetch( + ...this.prepareFetchOptions(path, options), + ); + if (response.status == 202) { + return undefined as T; + } + return response.json() as T; + } +} + +class AssistantsClient extends BaseClient { + /** + * Get an assistant by ID. + * + * @param assistantId The ID of the assistant. + * @returns Assistant + */ + async get(assistantId: string): Promise { + return this.fetch(`/assistants/${assistantId}`); + } + + /** + * Get the JSON representation of the graph assigned to a runnable + * @param assistantId The ID of the assistant. + * @returns Serialized graph + */ + async getGraph(assistantId: string): Promise { + return this.fetch(`/assistants/${assistantId}/graph`); + } + + /** + * Get the state and config schema of the graph assigned to a runnable + * @param assistantId The ID of the assistant. + * @returns Graph schema + */ + async getSchemas(assistantId: string): Promise { + return this.fetch(`/assistants/${assistantId}/schemas`); + } + + /** + * Create a new assistant. + * @param payload Payload for creating an assistant. + * @returns The created assistant. + */ + async create(payload: { + graphId: string; + config?: Config; + metadata?: Metadata; + }): Promise { + return this.fetch("/assistants", { + method: "POST", + json: { + graph_id: payload.graphId, + config: payload.config, + metadata: payload.metadata, + }, + }); + } + + /** + * Update an assistant. + * @param assistantId ID of the assistant. + * @param payload Payload for updating the assistant. + * @returns The updated assistant. + */ + async update( + assistantId: string, + payload: { + graphId: string; + config?: Config; + metadata?: Metadata; + }, + ): Promise { + return this.fetch(`/assistants/${assistantId}`, { + method: "PATCH", + json: { + graph_id: payload.graphId, + config: payload.config, + metadata: payload.metadata, + }, + }); + } + + /** + * Delete an assistant. + * + * @param assistantId ID of the assistant. + */ + async delete(assistantId: string): Promise { + return this.fetch(`/assistants/${assistantId}`, { + method: "DELETE", + }); + } + + /** + * List assistants. + * @param query Query options. + * @returns List of assistants. + */ + async search(query?: { + metadata?: Metadata; + limit?: number; + offset?: number; + }): Promise { + return this.fetch("/assistants/search", { + method: "POST", + json: { + metadata: query?.metadata ?? undefined, + limit: query?.limit ?? 10, + offset: query?.offset ?? 0, + }, + }); + } +} + +class ThreadsClient extends BaseClient { + /** + * Get a thread by ID. + * + * @param threadId ID of the thread. + * @returns The thread. + */ + async get(threadId: string): Promise { + return this.fetch(`/threads/${threadId}`); + } + + /** + * Create a new thread. + * + * @param payload Payload for creating a thread. + * @returns The created thread. + */ + async create(payload?: { + /** + * Metadata for the thread. + */ + metadata?: Metadata; + }): Promise { + return this.fetch(`/threads`, { + method: "POST", + json: { metadata: payload?.metadata }, + }); + } + + /** + * Update a thread. + * + * @param threadId ID of the thread. + * @param payload Payload for updating the thread. + * @returns The updated thread. + */ + async update( + threadId: string, + payload?: { + /** + * Metadata for the thread. + */ + metadata?: Metadata; + }, + ): Promise { + return this.fetch(`/threads/${threadId}`, { + method: "PATCH", + json: { metadata: payload?.metadata }, + }); + } + + /** + * Delete a thread. + * + * @param threadId ID of the thread. + */ + async delete(threadId: string): Promise { + return this.fetch(`/threads/${threadId}`, { + method: "DELETE", + }); + } + + /** + * List threads + * + * @param query Query options + * @returns List of threads + */ + async search(query?: { + /** + * Metadata to filter threads by. + */ + metadata?: Metadata; + /** + * Maximum number of threads to return. + * Defaults to 10 + */ + limit?: number; + /** + * Offset to start from. + */ + offset?: number; + }): Promise { + return this.fetch("/threads/search", { + method: "POST", + json: { + metadata: query?.metadata ?? undefined, + limit: query?.limit ?? 10, + offset: query?.offset ?? 0, + }, + }); + } + + /** + * Get state for a thread. + * + * @param threadId ID of the thread. + * @returns Thread state. + */ + async getState( + threadId: string, + checkpointId?: string, + ): Promise> { + return this.fetch>( + checkpointId != null + ? `/threads/${threadId}/state/${checkpointId}` + : `/threads/${threadId}/state`, + ); + } + + /** + * Add state to a thread. + * + * @param threadId The ID of the thread. + * @returns + */ + async updateState( + threadId: string, + options: { values: ValuesType; checkpointId?: string; asNode?: string }, + ): Promise { + return this.fetch(`/threads/${threadId}/state`, { + method: "POST", + json: { + values: options.values, + checkpoint_id: options.checkpointId, + as_node: options?.asNode, + }, + }); + } + + /** + * Patch the metadata of a thread. + * + * @param threadIdOrConfig Thread ID or config to patch the state of. + * @param metadata Metadata to patch the state with. + */ + async patchState( + threadIdOrConfig: string | Config, + metadata: Metadata, + ): Promise { + let threadId: string; + + if (typeof threadIdOrConfig !== "string") { + if (typeof threadIdOrConfig.configurable.thread_id !== "string") { + throw new Error( + "Thread ID is required when updating state with a config.", + ); + } + threadId = threadIdOrConfig.configurable.thread_id; + } else { + threadId = threadIdOrConfig; + } + + return this.fetch(`/threads/${threadId}/state`, { + method: "PATCH", + json: { metadata: metadata }, + }); + } + + /** + * Get all past states for a thread. + * + * @param threadId ID of the thread. + * @param options Additional options. + * @returns List of thread states. + */ + async getHistory( + threadId: string, + options?: { + limit?: number; + before?: Config; + metadata?: Metadata; + }, + ): Promise[]> { + return this.fetch[]>( + `/threads/${threadId}/history`, + { + method: "POST", + json: { + limit: options?.limit ?? 10, + before: options?.before, + metadata: options?.metadata, + }, + }, + ); + } +} + +class RunsClient extends BaseClient { + stream( + threadId: null, + assistantId: string, + payload?: Omit, + ): AsyncGenerator<{ + event: StreamEvent; + data: any; + }>; + + stream( + threadId: string, + assistantId: string, + payload?: RunsStreamPayload, + ): AsyncGenerator<{ + event: StreamEvent; + data: any; + }>; + + /** + * Create a run and stream the results. + * + * @param threadId The ID of the thread. + * @param assistantId Assistant ID to use for this run. + * @param payload Payload for creating a run. + */ + async *stream( + threadId: string | null, + assistantId: string, + payload?: RunsStreamPayload, + ): AsyncGenerator<{ + event: StreamEvent; + // TODO: figure out a better way to + // type this without any + data: any; + }> { + const json: Record = { + input: payload?.input, + config: payload?.config, + metadata: payload?.metadata, + stream_mode: payload?.streamMode, + feedback_keys: payload?.feedbackKeys, + assistant_id: assistantId, + interrupt_before: payload?.interruptBefore, + interrupt_after: payload?.interruptAfter, + }; + if (payload?.multitaskStrategy != null) { + json["multitask_strategy"] = payload?.multitaskStrategy; + } + + const endpoint = + threadId == null ? `/runs/stream` : `/threads/${threadId}/runs/stream`; + const response = await this.asyncCaller.fetch( + ...this.prepareFetchOptions(endpoint, { + method: "POST", + json, + signal: payload?.signal, + }), + ); + + let parser: EventSourceParser; + const textDecoder = new TextDecoder(); + + const stream: ReadableStream<{ event: string; data: any }> = ( + response.body || new ReadableStream({ start: (ctrl) => ctrl.close() }) + ).pipeThrough( + new TransformStream({ + async start(ctrl) { + parser = createParser((event) => { + if ( + (payload?.signal && payload.signal.aborted) || + (event.type === "event" && event.data === "[DONE]") + ) { + ctrl.terminate(); + return; + } + + if ("data" in event) { + ctrl.enqueue({ + event: event.event ?? "message", + data: JSON.parse(event.data), + }); + } + }); + }, + async transform(chunk) { + parser.feed(textDecoder.decode(chunk)); + }, + }), + ); + + yield* IterableReadableStream.fromReadableStream(stream); + } + + /** + * Create a run. + * + * @param threadId The ID of the thread. + * @param assistantId Assistant ID to use for this run. + * @param payload Payload for creating a run. + * @returns The created run. + */ + async create( + threadId: string, + assistantId: string, + payload?: RunsCreatePayload, + ): Promise { + const json: Record = { + input: payload?.input, + config: payload?.config, + metadata: payload?.metadata, + assistant_id: assistantId, + interrupt_before: payload?.interruptBefore, + interrupt_after: payload?.interruptAfter, + webhook: payload?.webhook, + }; + if (payload?.multitaskStrategy != null) { + json["multitask_strategy"] = payload?.multitaskStrategy; + } + return this.fetch(`/threads/${threadId}/runs`, { + method: "POST", + json, + signal: payload?.signal, + }); + } + + async wait( + threadId: null, + assistantId: string, + payload?: Omit, + ): Promise; + + async wait( + threadId: string, + assistantId: string, + payload?: RunsWaitPayload, + ): Promise; + + /** + * Create a run and wait for it to complete. + * + * @param threadId The ID of the thread. + * @param assistantId Assistant ID to use for this run. + * @param payload Payload for creating a run. + * @returns The last values chunk of the thread. + */ + async wait( + threadId: string | null, + assistantId: string, + payload?: RunsWaitPayload, + ): Promise { + const json: Record = { + input: payload?.input, + config: payload?.config, + metadata: payload?.metadata, + assistant_id: assistantId, + interrupt_before: payload?.interruptBefore, + interrupt_after: payload?.interruptAfter, + }; + if (payload?.multitaskStrategy != null) { + json["multitask_strategy"] = payload?.multitaskStrategy; + } + const endpoint = + threadId == null ? `/runs/wait` : `/threads/${threadId}/runs/wait`; + return this.fetch(endpoint, { + method: "POST", + json, + signal: payload?.signal, + }); + } + + /** + * List all runs for a thread. + * + * @param threadId The ID of the thread. + * @param options Filtering and pagination options. + * @returns List of runs. + */ + async list( + threadId: string, + options?: { + /** + * Maximum number of runs to return. + * Defaults to 10 + */ + limit?: number; + + /** + * Offset to start from. + * Defaults to 0. + */ + offset?: number; + }, + ): Promise { + return this.fetch(`/threads/${threadId}/runs`, { + params: { + limit: options?.limit ?? 10, + offset: options?.offset ?? 0, + }, + }); + } + + /** + * Get a run by ID. + * + * @param threadId The ID of the thread. + * @param runId The ID of the run. + * @returns The run. + */ + async get(threadId: string, runId: string): Promise { + return this.fetch(`/threads/${threadId}/runs/${runId}`); + } + + /** + * Cancel a run. + * + * @param threadId The ID of the thread. + * @param runId The ID of the run. + * @param wait Whether to block when canceling + * @returns + */ + async cancel( + threadId: string, + runId: string, + wait: boolean = false, + ): Promise { + return this.fetch(`/threads/${threadId}/runs/${runId}/cancel`, { + method: "POST", + params: { + wait: wait ? "1" : "0", + }, + }); + } + + /** + * Block until a run is done. + * + * @param threadId The ID of the thread. + * @param runId The ID of the run. + * @returns + */ + async join(threadId: string, runId: string): Promise { + return this.fetch(`/threads/${threadId}/runs/${runId}/join`); + } + + /** + * List all events for a run. + * + * @param threadId The ID of the thread. + * @param runId The ID of the run. + * @param options Filtering and pagination options. + * @returns List of events. + */ + async listEvents( + threadId: string, + runId: string, + options?: { + /** + * Maximum number of events to return. + * Defaults to 10 + */ + limit?: number; + /** + * Offset to start from. + * Defaults to 0. + */ + offset?: number; + }, + ): Promise { + return this.fetch(`/threads/${threadId}/runs/${runId}/events`, { + params: { + limit: options?.limit ?? 10, + offset: options?.offset ?? 0, + }, + }); + } + + /** + * Delete a run. + * + * @param threadId The ID of the thread. + * @param runId The ID of the run. + * @returns + */ + async delete(threadId: string, runId: string): Promise { + return this.fetch(`/threads/${threadId}/runs/${runId}`, { + method: "DELETE", + }); + } +} + +export class Client { + /** + * The client for interacting with assistants. + */ + public assistants: AssistantsClient; + + /** + * The client for interacting with threads. + */ + public threads: ThreadsClient; + + /** + * The client for interacting with runs. + */ + public runs: RunsClient; + + constructor(config?: ClientConfig) { + this.assistants = new AssistantsClient(config); + this.threads = new ThreadsClient(config); + this.runs = new RunsClient(config); + } +} diff --git a/libs/sdk-js/src/index.mts b/libs/sdk-js/src/index.mts new file mode 100644 index 000000000..b420f7df8 --- /dev/null +++ b/libs/sdk-js/src/index.mts @@ -0,0 +1,14 @@ +export { Client } from "./client.mjs"; + +export type { + Assistant, + AssistantGraph, + Config, + DefaultValues, + GraphSchema, + Metadata, + Run, + RunEvent, + Thread, + ThreadState, +} from "./schema.js"; diff --git a/libs/sdk-js/src/schema.ts b/libs/sdk-js/src/schema.ts new file mode 100644 index 000000000..b8d16cd2a --- /dev/null +++ b/libs/sdk-js/src/schema.ts @@ -0,0 +1,108 @@ +import type { JSONSchema7 } from "json-schema"; + +type Optional = T | null | undefined; + +export interface Config { + /** + * Tags for this call and any sub-calls (eg. a Chain calling an LLM). + * You can use these to filter calls. + */ + tags?: string[]; + + /** + * Maximum number of times a call can recurse. + * If not provided, defaults to 25. + */ + recursion_limit?: number; + + /** + * Runtime values for attributes previously made configurable on this Runnable. + */ + configurable: { + /** + * ID of the thread + */ + thread_id?: string; + + /** + * Timestamp of the state checkpoint + */ + thread_ts?: string; + [key: string]: unknown; + }; +} + +export interface GraphSchema { + /** + * The ID of the graph. + */ + graph_id: string; + + /** + * The schema for the graph state + */ + state_schema: JSONSchema7; + + /** + * The schema for the graph config + */ + config_schema: JSONSchema7; +} + +export type Metadata = Optional>; + +export interface Assistant { + assistant_id: string; + graph_id: string; + config: Config; + created_at: string; + updated_at: string; + metadata: Metadata; +} +export type AssistantGraph = Record>>; + +export interface Thread { + thread_id: string; + created_at: string; + updated_at: string; + metadata: Metadata; +} + +export type DefaultValues = Record[] | Record; + +export interface ThreadState { + values: ValuesType; + next: string[]; + checkpoint_id: string; + metadata: Metadata; + created_at: Optional; + parent_checkpoint_id: Optional; +} + +export interface Run { + run_id: string; + thread_id: string; + assistant_id: string; + created_at: string; + updated_at: string; + status: + | "pending" + | "running" + | "error" + | "success" + | "timeout" + | "interrupted"; + metadata: Metadata; +} + +export interface RunEvent { + event_id: string; + run_id: string; + received_at: string; + span_id: string; + event: string; + name: string; + data: Record; + metadata: Record; + tags: string[]; +} diff --git a/libs/sdk-js/src/types.mts b/libs/sdk-js/src/types.mts new file mode 100644 index 000000000..c5ddaa5b4 --- /dev/null +++ b/libs/sdk-js/src/types.mts @@ -0,0 +1,86 @@ +import { Config, Metadata } from "./schema.js"; + +export type StreamMode = "values" | "messages" | "updates" | "events" | "debug"; +export type MultitaskStrategy = "reject" | "interrupt" | "rollback" | "enqueue"; +export type StreamEvent = + | "events" + | "metadata" + | "debug" + | "updates" + | "values" + | "messages/partial" + | "messages/metadata" + | "messages/complete" + | (string & {}); + +interface RunsInvokePayload { + /** + * Input to the run. Pass `null` to resume from the current state of the thread. + */ + input?: Record | null; + + /** + * Metadata for the run. + */ + metadata?: Metadata; + + /** + * Additional configuration for the run. + */ + config?: Config; + + /** + * Interrupt execution before entering these nodes. + */ + interruptBefore?: string[]; + + /** + * Interrupt execution after leaving these nodes. + */ + interruptAfter?: string[]; + + /** + * Strategy to handle concurrent runs on the same thread. Only relevant if + * there is a pending/inflight run on the same thread. One of: + * - "reject": Reject the new run. + * - "interrupt": Interrupt the current run, keeping steps completed until now, + and start a new one. + * - "rollback": Cancel and delete the existing run, rolling back the thread to + the state before it had started, then start the new run. + * - "enqueue": Queue up the new run to start after the current run finishes. + */ + multitaskStrategy?: MultitaskStrategy; + + /** + * Abort controller signal to cancel the run. + */ + signal?: AbortController["signal"]; +} + +export interface RunsStreamPayload extends RunsInvokePayload { + /** + * One of `"values"`, `"messages"`, `"updates"` or `"events"`. + * - `"values"`: Stream the thread state any time it changes. + * - `"messages"`: Stream chat messages from thread state and calls to chat models, + * token-by-token where possible. + * - `"updates"`: Stream the state updates returned by each node. + * - `"events"`: Stream all events produced by the run. You can also access these + * afterwards using the `client.runs.listEvents()` method. + */ + streamMode?: StreamMode | Array; + + /** + * Pass one or more feedbackKeys if you want to request short-lived signed URLs + * for submitting feedback to LangSmith with this key for this run. + */ + feedbackKeys?: string[]; +} + +export interface RunsCreatePayload extends RunsInvokePayload { + /** + * Webhook to call when the run is complete. + */ + webhook?: string; +} + +export type RunsWaitPayload = RunsStreamPayload; diff --git a/libs/sdk-js/src/utils/async_caller.mts b/libs/sdk-js/src/utils/async_caller.mts new file mode 100644 index 000000000..1774b9609 --- /dev/null +++ b/libs/sdk-js/src/utils/async_caller.mts @@ -0,0 +1,206 @@ +import pRetry from "p-retry"; +import PQueueMod from "p-queue"; + +const STATUS_NO_RETRY = [ + 400, // Bad Request + 401, // Unauthorized + 403, // Forbidden + 404, // Not Found + 405, // Method Not Allowed + 406, // Not Acceptable + 407, // Proxy Authentication Required + 408, // Request Timeout + 422, // Unprocessable Entity +]; +const STATUS_IGNORE = [ + 409, // Conflict +]; + +type ResponseCallback = (response?: Response) => Promise; + +export interface AsyncCallerParams { + /** + * The maximum number of concurrent calls that can be made. + * Defaults to `Infinity`, which means no limit. + */ + maxConcurrency?: number; + /** + * The maximum number of retries that can be made for a single call, + * with an exponential backoff between each attempt. Defaults to 6. + */ + maxRetries?: number; + + onFailedResponseHook?: ResponseCallback; +} + +export interface AsyncCallerCallOptions { + signal?: AbortSignal; +} + +/** + * Do not rely on globalThis.Response, rather just + * do duck typing + */ +function isResponse(x: unknown): x is Response { + if (x == null || typeof x !== "object") return false; + return "status" in x && "statusText" in x && "text" in x; +} + +/** + * Utility error to properly handle failed requests + */ +class HTTPError extends Error { + status: number; + text: string; + + response?: Response; + + constructor(status: number, message: string, response?: Response) { + super(`HTTP ${status}: ${message}`); + this.status = status; + this.text = message; + this.response = response; + } + + static async fromResponse( + response: Response, + options?: { includeResponse?: boolean }, + ): Promise { + try { + return new HTTPError( + response.status, + await response.text(), + options?.includeResponse ? response : undefined, + ); + } catch { + return new HTTPError( + response.status, + response.statusText, + options?.includeResponse ? response : undefined, + ); + } + } +} + +/** + * A class that can be used to make async calls with concurrency and retry logic. + * + * This is useful for making calls to any kind of "expensive" external resource, + * be it because it's rate-limited, subject to network issues, etc. + * + * Concurrent calls are limited by the `maxConcurrency` parameter, which defaults + * to `Infinity`. This means that by default, all calls will be made in parallel. + * + * Retries are limited by the `maxRetries` parameter, which defaults to 5. This + * means that by default, each call will be retried up to 5 times, with an + * exponential backoff between each attempt. + */ +export class AsyncCaller { + protected maxConcurrency: AsyncCallerParams["maxConcurrency"]; + + protected maxRetries: AsyncCallerParams["maxRetries"]; + + private queue: (typeof import("p-queue"))["default"]["prototype"]; + + private onFailedResponseHook?: ResponseCallback; + + constructor(params: AsyncCallerParams) { + this.maxConcurrency = params.maxConcurrency ?? Infinity; + this.maxRetries = params.maxRetries ?? 4; + + if ("default" in PQueueMod) { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.queue = new (PQueueMod.default as any)({ + concurrency: this.maxConcurrency, + }); + } else { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + this.queue = new (PQueueMod as any)({ concurrency: this.maxConcurrency }); + } + this.onFailedResponseHook = params?.onFailedResponseHook; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + call Promise>( + callable: T, + ...args: Parameters + ): Promise>> { + const onFailedResponseHook = this.onFailedResponseHook; + return this.queue.add( + () => + pRetry( + () => + callable(...(args as Parameters)).catch(async (error) => { + // eslint-disable-next-line no-instanceof/no-instanceof + if (error instanceof Error) { + throw error; + } else if (isResponse(error)) { + throw await HTTPError.fromResponse(error, { + includeResponse: !!onFailedResponseHook, + }); + } else { + throw new Error(error); + } + }), + { + async onFailedAttempt(error) { + if ( + error.message.startsWith("Cancel") || + error.message.startsWith("TimeoutError") || + error.message.startsWith("AbortError") + ) { + throw error; + } + // eslint-disable-next-line @typescript-eslint/no-explicit-any + if ((error as any)?.code === "ECONNABORTED") { + throw error; + } + + if (error instanceof HTTPError) { + if (STATUS_NO_RETRY.includes(error.status)) { + throw error; + } else if (STATUS_IGNORE.includes(error.status)) { + return; + } + if (onFailedResponseHook && error.response) { + await onFailedResponseHook(error.response); + } + } + }, + // If needed we can change some of the defaults here, + // but they're quite sensible. + retries: this.maxRetries, + randomize: true, + }, + ), + { throwOnTimeout: true }, + ); + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + callWithOptions Promise>( + options: AsyncCallerCallOptions, + callable: T, + ...args: Parameters + ): Promise>> { + // Note this doesn't cancel the underlying request, + // when available prefer to use the signal option of the underlying call + if (options.signal) { + return Promise.race([ + this.call(callable, ...args), + new Promise((_, reject) => { + options.signal?.addEventListener("abort", () => { + reject(new Error("AbortError")); + }); + }), + ]); + } + return this.call(callable, ...args); + } + + fetch(...args: Parameters): ReturnType { + return this.call(() => + fetch(...args).then((res) => (res.ok ? res : Promise.reject(res))), + ); + } +} diff --git a/libs/sdk-js/src/utils/stream.mts b/libs/sdk-js/src/utils/stream.mts new file mode 100644 index 000000000..c921ddf51 --- /dev/null +++ b/libs/sdk-js/src/utils/stream.mts @@ -0,0 +1,109 @@ +// in this case don't quite match. +type IterableReadableStreamInterface = ReadableStream & AsyncIterable; + +/* + * Support async iterator syntax for ReadableStreams in all environments. + * Source: https://github.com/MattiasBuelens/web-streams-polyfill/pull/122#issuecomment-1627354490 + */ +export class IterableReadableStream + extends ReadableStream + implements IterableReadableStreamInterface +{ + public reader: ReadableStreamDefaultReader; + + ensureReader() { + if (!this.reader) { + this.reader = this.getReader(); + } + } + + async next(): Promise> { + this.ensureReader(); + try { + const result = await this.reader.read(); + if (result.done) { + this.reader.releaseLock(); // release lock when stream becomes closed + return { + done: true, + value: undefined, + }; + } else { + return { + done: false, + value: result.value, + }; + } + } catch (e) { + this.reader.releaseLock(); // release lock when stream becomes errored + throw e; + } + } + + async return(): Promise> { + this.ensureReader(); + // If wrapped in a Node stream, cancel is already called. + if (this.locked) { + const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet + this.reader.releaseLock(); // release lock first + await cancelPromise; // now await it + } + return { done: true, value: undefined }; + } + + // eslint-disable-next-line @typescript-eslint/no-explicit-any + async throw(e: any): Promise> { + this.ensureReader(); + if (this.locked) { + const cancelPromise = this.reader.cancel(); // cancel first, but don't await yet + this.reader.releaseLock(); // release lock first + await cancelPromise; // now await it + } + throw e; + } + + [Symbol.asyncIterator]() { + return this; + } + + static fromReadableStream(stream: ReadableStream) { + // From https://developer.mozilla.org/en-US/docs/Web/API/Streams_API/Using_readable_streams#reading_the_stream + const reader = stream.getReader(); + return new IterableReadableStream({ + start(controller) { + return pump(); + function pump(): Promise { + return reader.read().then(({ done, value }) => { + // When no more data needs to be consumed, close the stream + if (done) { + controller.close(); + return; + } + // Enqueue the next data chunk into our target stream + controller.enqueue(value); + return pump(); + }); + } + }, + cancel() { + reader.releaseLock(); + }, + }); + } + + static fromAsyncGenerator(generator: AsyncGenerator) { + return new IterableReadableStream({ + async pull(controller) { + const { value, done } = await generator.next(); + // When no more data needs to be consumed, close the stream + if (done) { + controller.close(); + } + // Fix: `else if (value)` will hang the streaming when nullish value (e.g. empty string) is pulled + controller.enqueue(value); + }, + async cancel(reason) { + await generator.return(reason); + }, + }); + } +} diff --git a/libs/sdk-js/tsconfig.cjs.json b/libs/sdk-js/tsconfig.cjs.json new file mode 100644 index 000000000..7e091b100 --- /dev/null +++ b/libs/sdk-js/tsconfig.cjs.json @@ -0,0 +1,7 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "declaration": false + }, + "exclude": ["node_modules", "dist", "**/tests"] +} diff --git a/libs/sdk-js/tsconfig.json b/libs/sdk-js/tsconfig.json new file mode 100644 index 000000000..355f38ad2 --- /dev/null +++ b/libs/sdk-js/tsconfig.json @@ -0,0 +1,26 @@ +{ + "extends": "@tsconfig/recommended", + "compilerOptions": { + "target": "ES2021", + "lib": ["ES2021", "ES2022.Object", "DOM"], + "module": "NodeNext", + "moduleResolution": "nodenext", + "esModuleInterop": true, + "declaration": true, + "noImplicitReturns": true, + "noFallthroughCasesInSwitch": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "useDefineForClassFields": true, + "strictPropertyInitialization": false, + "allowJs": true, + "strict": true, + "outDir": "dist" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "coverage"], + "includeVersion": true, + "typedocOptions": { + "entryPoints": ["src/client.ts"] + } +} diff --git a/libs/sdk-js/yarn.lock b/libs/sdk-js/yarn.lock new file mode 100644 index 000000000..b49c759a3 --- /dev/null +++ b/libs/sdk-js/yarn.lock @@ -0,0 +1,93 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@tsconfig/recommended@^1.0.2": + version "1.0.6" + resolved "https://registry.yarnpkg.com/@tsconfig/recommended/-/recommended-1.0.6.tgz#217b78f9601215939d566a79d202a760ae185114" + integrity sha512-0IKu9GHYF1NGTJiYgfWwqnOQSlnE9V9R7YohHNNf0/fj/SyOZWzdd06JFr0fLpg1Mqw0kGbYg8w5xdkSqLKM9g== + +"@types/json-schema@^7.0.15": + version "7.0.15" + resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + +"@types/node@^20.12.12": + version "20.12.12" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.12.tgz#7cbecdf902085cec634fdb362172dfe12b8f2050" + integrity sha512-eWLDGF/FOSPtAvEqeRAQ4C8LSA7M1I7i0ky1I8U7kD1J5ITyW3AsRhQrKVoWf5pFKZ2kILsEGJhsI9r93PYnOw== + dependencies: + undici-types "~5.26.4" + +"@types/retry@0.12.0": + version "0.12.0" + resolved "https://registry.yarnpkg.com/@types/retry/-/retry-0.12.0.tgz#2b35eccfcee7d38cd72ad99232fbd58bffb3c84d" + integrity sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA== + +"@types/uuid@^9.0.1": + version "9.0.8" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-9.0.8.tgz#7545ba4fc3c003d6c756f651f3bf163d8f0f29ba" + integrity sha512-jg+97EGIcY9AGHJJRaaPVgetKDsrTgbRjQ5Msgjh/DQKEFl0DtyRr/VCOyD1T2R1MNeWPK/u7JoGhlDZnKBAfA== + +eventemitter3@^4.0.4: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eventsource-parser@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/eventsource-parser/-/eventsource-parser-1.1.2.tgz#ed6154a4e3dbe7cda9278e5e35d2ffc58b309f89" + integrity sha512-v0eOBUbiaFojBu2s2NPBfYUoRR9GjcDNvCXVaqEf5vVfpIAh9f8RCo4vXTP8c63QRKCFwoLpMpTdPwwhEKVgzA== + +p-finally@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + integrity sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow== + +p-queue@^6.6.2: + version "6.6.2" + resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" + integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== + dependencies: + eventemitter3 "^4.0.4" + p-timeout "^3.2.0" + +p-retry@4: + version "4.6.2" + resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-4.6.2.tgz#9baae7184057edd4e17231cee04264106e092a16" + integrity sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ== + dependencies: + "@types/retry" "0.12.0" + retry "^0.13.1" + +p-timeout@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" + integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== + dependencies: + p-finally "^1.0.0" + +prettier@^3.2.5: + version "3.2.5" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" + integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== + +retry@^0.13.1: + version "0.13.1" + resolved "https://registry.yarnpkg.com/retry/-/retry-0.13.1.tgz#185b1587acf67919d63b357349e03537b2484658" + integrity sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg== + +typescript@^5.4.5: + version "5.4.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611" + integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +uuid@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-9.0.1.tgz#e188d4c8853cc722220392c424cd637f32293f30" + integrity sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA== diff --git a/libs/sdk-py/LICENSE b/libs/sdk-py/LICENSE new file mode 100644 index 000000000..fc0602fee --- /dev/null +++ b/libs/sdk-py/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 LangChain, Inc. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/libs/sdk-py/Makefile b/libs/sdk-py/Makefile new file mode 100644 index 000000000..d3707c2f8 --- /dev/null +++ b/libs/sdk-py/Makefile @@ -0,0 +1,10 @@ +.PHONY: lint format + +lint: + poetry run ruff check . + poetry run ruff format . --diff + poetry run mypy . + +format: + poetry run ruff format . + poetry run ruff check --select I --fix . diff --git a/libs/sdk-py/README.md b/libs/sdk-py/README.md new file mode 100644 index 000000000..66351bf01 --- /dev/null +++ b/libs/sdk-py/README.md @@ -0,0 +1 @@ +# langgraph diff --git a/libs/sdk-py/langgraph_sdk/__init__.py b/libs/sdk-py/langgraph_sdk/__init__.py new file mode 100644 index 000000000..4af615310 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/__init__.py @@ -0,0 +1,10 @@ +from langgraph_sdk.client import get_client + +try: + from importlib import metadata + + __version__ = metadata.version(__package__) +except metadata.PackageNotFoundError: + __version__ = "unknown" + +__all__ = ["get_client"] diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py new file mode 100644 index 000000000..d07094c61 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -0,0 +1,610 @@ +from __future__ import annotations + +import asyncio +import logging +import os +import sys +from typing import Any, AsyncIterator, Dict, List, NamedTuple, Optional, Union, overload + +import httpx +import httpx_sse +import orjson +from httpx._types import QueryParamTypes + +import langgraph_sdk +from langgraph_sdk.schema import ( + Assistant, + Config, + GraphSchema, + Metadata, + MultitaskStrategy, + Run, + RunEvent, + StreamMode, + Thread, + ThreadState, +) + +logger = logging.getLogger(__name__) + + +def get_client( + *, url: str = "http://localhost:8123", api_key: Optional[str] = None +) -> LangGraphClient: + """Get a LangGraphClient instance. + + Args: + url (str, optional): The URL of the LangGraph API. Defaults to "http://localhost:8123". + api_key (str, optional): The API key. If not provided, it will be read from the environment. + Precedence: + 1. explicit argument + 2. LANGGRAPH_API_KEY + 3. LANGSMITH_API_KEY + 4. LANGCHAIN_API_KEY + """ + headers = { + "User-Agent": f"langgraph-sdk-py/{langgraph_sdk.__version__}", + } + api_key = _get_api_key(api_key) + if api_key: + headers["x-api-key"] = api_key + client = httpx.AsyncClient( + base_url=url, + transport=httpx.AsyncHTTPTransport(retries=5), + timeout=httpx.Timeout(connect=5, read=60, write=60, pool=5), + headers=headers, + ) + return LangGraphClient(client) + + +class StreamPart(NamedTuple): + event: str + data: dict + + +class LangGraphClient: + def __init__(self, client: httpx.AsyncClient) -> None: + self.http = HttpClient(client) + self.assistants = AssistantsClient(self.http) + self.threads = ThreadsClient(self.http) + self.runs = RunsClient(self.http) + + +class HttpClient: + def __init__(self, client: httpx.AsyncClient) -> None: + self.client = client + + async def get(self, path: str, *, params: Optional[QueryParamTypes] = None) -> Any: + """Make a GET request.""" + r = await self.client.get(path, params=params) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + return await decode_json(r) + + async def post(self, path: str, *, json: Optional[dict]) -> Any: + """Make a POST request.""" + if json is not None: + headers, content = await encode_json(json) + else: + headers, content = {}, b"" + r = await self.client.post(path, headers=headers, content=content) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + return await decode_json(r) + + async def put(self, path: str, *, json: dict) -> Any: + """Make a PUT request.""" + headers, content = await encode_json(json) + r = await self.client.put(path, headers=headers, content=content) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + return await decode_json(r) + + async def patch(self, path: str, *, json: dict) -> Any: + """Make a PATCH request.""" + headers, content = await encode_json(json) + r = await self.client.patch(path, headers=headers, content=content) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + return await decode_json(r) + + async def delete(self, path: str) -> None: + """Make a DELETE request.""" + r = await self.client.delete(path) + try: + r.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await r.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + + async def stream( + self, path: str, method: str, *, json: Optional[dict] = None + ) -> AsyncIterator[StreamPart]: + """Stream the results of a request using SSE.""" + headers, content = await encode_json(json) + async with httpx_sse.aconnect_sse( + self.client, method, path, headers=headers, content=content + ) as sse: + try: + sse.response.raise_for_status() + except httpx.HTTPStatusError as e: + body = (await sse.response.aread()).decode() + if sys.version_info >= (3, 11): + e.add_note(body) + else: + logger.error(f"Error from langgraph-api: {body}", exc_info=e) + raise e + async for event in sse.aiter_sse(): + yield StreamPart( + event.event, orjson.loads(event.data) if event.data else None + ) + + +def _orjson_default(obj: Any) -> Any: + if hasattr(obj, "model_dump") and callable(obj.model_dump): + return obj.model_dump() + elif hasattr(obj, "dict") and callable(obj.dict): + return obj.dict() + elif isinstance(obj, (set, frozenset)): + return list(obj) + else: + raise TypeError(f"Object of type {type(obj)} is not JSON serializable") + + +async def encode_json(json: Any) -> tuple[dict[str, str], bytes]: + body = await asyncio.get_running_loop().run_in_executor( + None, + orjson.dumps, + json, + _orjson_default, + orjson.OPT_SERIALIZE_NUMPY | orjson.OPT_NON_STR_KEYS, + ) + content_length = str(len(body)) + content_type = "application/json" + headers = {"Content-Length": content_length, "Content-Type": content_type} + return headers, body + + +async def decode_json(r: httpx.Response) -> Any: + body = await r.aread() + return ( + await asyncio.get_running_loop().run_in_executor(None, orjson.loads, body) + if body + else None + ) + + +class AssistantsClient: + def __init__(self, http: HttpClient) -> None: + self.http = http + + async def get(self, assistant_id: str) -> Assistant: + """Get an assistant by ID.""" + return await self.http.get(f"/assistants/{assistant_id}") + + async def get_graph(self, assistant_id: str) -> dict[str, list[dict[str, Any]]]: + """Get the graph of an assistant by ID.""" + return await self.http.get(f"/assistants/{assistant_id}/graph") + + async def get_schemas(self, assistant_id: str) -> GraphSchema: + """Get the schemas of an assistant by ID.""" + return await self.http.get(f"/assistants/{assistant_id}/schemas") + + async def create( + self, + graph_id: Optional[str], + config: Optional[Config] = None, + *, + metadata: Metadata = None, + assistant_id: Optional[str] = None, + ) -> Assistant: + """Create a new assistant.""" + payload = { + "metadata": metadata, + "graph_id": graph_id, + "config": config or {}, + } + if assistant_id: + payload["assistant_id"] = assistant_id + return await self.http.post("/assistants", json=payload) + + async def update( + self, + assistant_id: str, + *, + graph_id: Optional[str] = None, + config: Optional[Config] = None, + metadata: Metadata = None, + ) -> Assistant: + """Update an assistant.""" + return await self.http.patch( + f"/assistants/{assistant_id}", + json={"metadata": metadata, "graph_id": graph_id, "config": config}, + ) + + async def delete( + self, + assistant_id: str, + ) -> None: + """Delete an assistant.""" + await self.http.delete(f"/assistants/{assistant_id}") + + async def search( + self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0 + ) -> list[Assistant]: + """Search for assistants.""" + return await self.http.post( + "/assistants/search", + json={"metadata": metadata, "limit": limit, "offset": offset}, + ) + + +class ThreadsClient: + def __init__(self, http: HttpClient) -> None: + self.http = http + + async def get(self, thread_id: str) -> Thread: + """Get a thread by ID.""" + return await self.http.get(f"/threads/{thread_id}") + + async def create( + self, + *, + metadata: Metadata = None, + thread_id: Optional[str] = None, + ) -> Thread: + """Create a new thread.""" + payload: Dict[str, Any] = {"metadata": metadata} + if thread_id: + payload["thread_id"] = thread_id + return await self.http.post("/threads", json=payload) + + async def update(self, thread_id: str, *, metadata: Metadata = None) -> Thread: + """Update a thread.""" + return await self.http.patch( + f"/threads/{thread_id}", json={"metadata": metadata} + ) + + async def delete(self, thread_id: str) -> None: + """Delete a thread.""" + await self.http.delete(f"/threads/{thread_id}") + + async def search( + self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0 + ) -> list[Thread]: + """Search for threads.""" + return await self.http.post( + "/threads/search", + json={"metadata": metadata, "limit": limit, "offset": offset}, + ) + + async def get_state( + self, thread_id: str, checkpoint_id: Optional[str] = None + ) -> ThreadState: + """Get the state of a thread.""" + if checkpoint_id: + return await self.http.get(f"/threads/{thread_id}/state/{checkpoint_id}") + else: + return await self.http.get(f"/threads/{thread_id}/state") + + async def update_state( + self, + thread_id: str, + values: dict, + *, + as_node: Optional[str] = None, + checkpoint_id: Optional[str] = None, + ) -> None: + """Update the state of a thread.""" + return await self.http.post( + f"/threads/{thread_id}/state", + json={"values": values, "checkpoint_id": checkpoint_id, "as_node": as_node}, + ) + + async def patch_state( + self, + thread_id: Union[str, Config], + metadata: dict, + ) -> None: + """Patch the state of a thread.""" + if isinstance(thread_id, dict): + thread_id_: str = thread_id["configurable"]["thread_id"] + else: + thread_id_ = thread_id + return await self.http.patch( + f"/threads/{thread_id_}/state", + json={"metadata": metadata}, + ) + + async def get_history( + self, + thread_id: str, + limit: int = 10, + before: Optional[str] = None, + metadata: Optional[dict] = None, + ) -> list[ThreadState]: + """Get the history of a thread.""" + return await self.http.post( + f"/threads/{thread_id}/history", + json={"limit": limit, "before": before, "metadata": metadata}, + ) + + +class RunsClient: + def __init__(self, http: HttpClient) -> None: + self.http = http + + @overload + def stream( + self, + thread_id: str, + assistant_id: str, + *, + input: Optional[dict] = None, + stream_mode: Union[StreamMode, list[StreamMode]] = "values", + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + feedback_keys: Optional[list[str]] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> AsyncIterator[StreamPart]: + ... + + @overload + def stream( + self, + thread_id: None, + assistant_id: str, + *, + input: Optional[dict] = None, + stream_mode: Union[StreamMode, list[StreamMode]] = "values", + metadata: Optional[dict] = None, + config: Optional[Config] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + feedback_keys: Optional[list[str]] = None, + ) -> AsyncIterator[StreamPart]: + ... + + def stream( + self, + thread_id: Optional[str], + assistant_id: str, + *, + input: Optional[dict] = None, + stream_mode: Union[StreamMode, list[StreamMode]] = "values", + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + feedback_keys: Optional[list[str]] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> AsyncIterator[StreamPart]: + """Create a run and stream the results.""" + payload = { + "input": input, + "config": config, + "metadata": metadata, + "stream_mode": stream_mode, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "feedback_keys": feedback_keys, + "checkpoint_id": checkpoint_id, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + + endpoint = ( + f"/threads/{thread_id}/runs/stream" + if thread_id is not None + else "/runs/stream" + ) + return self.http.stream(endpoint, "POST", json=payload) + + @overload + async def create( + self, + thread_id: None, + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + webhook: Optional[str] = None, + ) -> Run: + ... + + @overload + async def create( + self, + thread_id: str, + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + webhook: Optional[str] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> Run: + ... + + async def create( + self, + thread_id: Optional[str], + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + webhook: Optional[str] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> Run: + """Create a background run.""" + payload = { + "input": input, + "config": config, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + "checkpoint_id": checkpoint_id, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + if thread_id: + return await self.http.post(f"/threads/{thread_id}/runs", json=payload) + else: + return await self.http.post("/runs", json=payload) + + @overload + async def wait( + self, + thread_id: str, + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> Union[list[dict], dict[str, Any]]: + ... + + @overload + async def wait( + self, + thread_id: None, + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + ) -> Union[list[dict], dict[str, Any]]: + ... + + async def wait( + self, + thread_id: Optional[str], + assistant_id: str, + *, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + checkpoint_id: Optional[str] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + multitask_strategy: Optional[MultitaskStrategy] = None, + ) -> Union[list[dict], dict[str, Any]]: + """Create a run, wait for and return the final state.""" + payload = { + "input": input, + "config": config, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "checkpoint_id": checkpoint_id, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + + endpoint = ( + f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" + ) + return await self.http.post(endpoint, json=payload) + + async def list( + self, thread_id: str, *, limit: int = 10, offset: int = 0 + ) -> List[Run]: + """List runs.""" + return await self.http.get(f"/threads/{thread_id}/runs") + + async def get(self, thread_id: str, run_id: str) -> Run: + """Get a run.""" + return await self.http.get(f"/threads/{thread_id}/runs/{run_id}") + + async def cancel(self, thread_id: str, run_id: str, *, wait: bool = False) -> None: + """Get a run.""" + return await self.http.post( + f"/threads/{thread_id}/runs/{run_id}/cancel?wait={1 if wait else 0}", + json=None, + ) + + async def join(self, thread_id: str, run_id: str) -> None: + """Block until a run is done.""" + return await self.http.get(f"/threads/{thread_id}/runs/{run_id}/join") + + async def list_events( + self, thread_id: str, run_id: str, *, limit: int = 10, offset: int = 0 + ) -> List[RunEvent]: + """List run events.""" + return await self.http.get(f"/threads/{thread_id}/runs/{run_id}/events") + + async def delete(self, thread_id: str, run_id: str) -> None: + """Delete a run.""" + await self.http.delete(f"/threads/{thread_id}/runs/{run_id}") + + +def _get_api_key(api_key: Optional[str] = None) -> Optional[str]: + """Get the API key from the environment. + Precedence: + 1. explicit argument + 2. LANGGRAPH_API_KEY + 3. LANGSMITH_API_KEY + 4. LANGCHAIN_API_KEY + """ + if api_key: + return api_key + for prefix in ["LANGGRAPH", "LANGSMITH", "LANGCHAIN"]: + if env := os.getenv(f"{prefix}_API_KEY"): + return env.strip().strip('"').strip("'") + return None # type: ignore diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py new file mode 100644 index 000000000..dc1097183 --- /dev/null +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -0,0 +1,128 @@ +from datetime import datetime +from typing import Any, Literal, Optional, Sequence, TypedDict, Union + +Metadata = Optional[dict[str, Any]] + +RunStatus = Literal["pending", "running", "error", "success", "timeout", "interrupted"] + +StreamMode = Literal["values", "messages", "updates", "events", "debug"] + +MultitaskStrategy = Literal["reject", "interrupt", "rollback", "enqueue"] + +All = Literal["*"] + + +class Config(TypedDict, total=False): + tags: list[str] + """ + Tags for this call and any sub-calls (eg. a Chain calling an LLM). + You can use these to filter calls. + """ + + recursion_limit: int + """ + Maximum number of times a call can recurse. If not provided, defaults to 25. + """ + + configurable: dict[str, Any] + """ + Runtime values for attributes previously made configurable on this Runnable, + or sub-Runnables, through .configurable_fields() or .configurable_alternatives(). + Check .output_schema() for a description of the attributes that have been made + configurable. + """ + + +class GraphSchema(TypedDict): + """Graph model.""" + + graph_id: str + """The ID of the graph.""" + state_schema: dict + """The schema for the graph state.""" + config_schema: dict + """The schema for the graph config.""" + + +class Assistant(TypedDict): + """Assistant model.""" + + assistant_id: str + """The ID of the assistant.""" + graph_id: str + """The ID of the graph.""" + config: Config + """The assistant config.""" + created_at: datetime + """The time the assistant was created.""" + updated_at: datetime + """The last time the assistant was updated.""" + metadata: Metadata + """The assistant metadata.""" + + +class Thread(TypedDict): + thread_id: str + """The ID of the thread.""" + created_at: datetime + """The time the thread was created.""" + updated_at: datetime + """The last time the thread was updated.""" + metadata: Metadata + """The thread metadata.""" + multitask_strategy: MultitaskStrategy + """The multitask strategy for this thread.""" + + +class ThreadState(TypedDict): + values: Union[list[dict], dict[str, Any]] + """The state values.""" + next: Sequence[str] + """The next nodes to execute. If empty, the thread is done until new input is + received.""" + checkpoint_id: str + """The ID of the checkpoint.""" + metadata: Metadata + """Metadata for this state""" + created_at: Optional[str] + """Timestamp of state creation""" + parent_checkpoint_id: Optional[str] + """The ID of the parent checkpoint. If missing, this is the root checkpoint.""" + + +class Run(TypedDict): + run_id: str + """The ID of the run.""" + thread_id: str + """The ID of the thread.""" + assistant_id: str + """The assistant that was used for this run.""" + created_at: datetime + """The time the run was created.""" + updated_at: datetime + """The last time the run was updated.""" + status: RunStatus + """The status of the run. One of 'pending', 'running', 'error', 'success'.""" + metadata: Metadata + """The run metadata.""" + + +class RunEvent(TypedDict): + event_id: str + """The ID of the event.""" + run_id: str + """The ID of the run.""" + received_at: datetime + """The time the event was received.""" + span_id: str + """The ID of the span.""" + event: str + """The event type.""" + name: str + """The event name.""" + data: dict + """The event data.""" + metadata: dict + """The event metadata.""" + tags: list[str] + """The event tags.""" diff --git a/libs/sdk-py/poetry.lock b/libs/sdk-py/poetry.lock new file mode 100644 index 000000000..9f714f5de --- /dev/null +++ b/libs/sdk-py/poetry.lock @@ -0,0 +1,492 @@ +# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. + +[[package]] +name = "anyio" +version = "4.3.0" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +optional = false +python-versions = ">=3.8" +files = [ + {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, + {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, +] + +[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.2.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.2.2-py3-none-any.whl", hash = "sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1"}, + {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, +] + +[[package]] +name = "codespell" +version = "2.2.6" +description = "Codespell" +optional = false +python-versions = ">=3.8" +files = [ + {file = "codespell-2.2.6-py3-none-any.whl", hash = "sha256:9ee9a3e5df0990604013ac2a9f22fa8e57669c827124a2e961fe8a1da4cacc07"}, + {file = "codespell-2.2.6.tar.gz", hash = "sha256:a8c65d8eb3faa03deabab6b3bbe798bea72e1799c7e9e955d57eca4096abcff9"}, +] + +[package.extras] +dev = ["Pygments", "build", "chardet", "pre-commit", "pytest", "pytest-cov", "pytest-dependency", "ruff", "tomli", "twine"] +hard-encoding-detection = ["chardet"] +toml = ["tomli"] +types = ["chardet (>=5.1.0)", "mypy", "pytest", "pytest-cov", "pytest-dependency"] + +[[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" +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 = "docopt" +version = "0.6.2" +description = "Pythonic argument parser, that will make you smile" +optional = false +python-versions = "*" +files = [ + {file = "docopt-0.6.2.tar.gz", hash = "sha256:49b3a825280bd66b3aa83585ef59c4a8c82f2c8a522dbe754a8bc8d08c85c491"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +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.14.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.7" +files = [ + {file = "h11-0.14.0-py3-none-any.whl", hash = "sha256:e3fe4ac4b851c468cc8363d500db52c2ead036020723024a109d37346efaa761"}, + {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, +] + +[[package]] +name = "httpcore" +version = "1.0.5" +description = "A minimal low-level HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpcore-1.0.5-py3-none-any.whl", hash = "sha256:421f18bac248b25d310f3cacd198d55b8e6125c107797b609ff9b7a6ba7991b5"}, + {file = "httpcore-1.0.5.tar.gz", hash = "sha256:34a38e2f9291467ee3b44e89dd52615370e152954ba21721378a87b2960f7a61"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.13,<0.15" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<0.26.0)"] + +[[package]] +name = "httpx" +version = "0.27.0" +description = "The next generation HTTP client." +optional = false +python-versions = ">=3.8" +files = [ + {file = "httpx-0.27.0-py3-none-any.whl", hash = "sha256:71d5465162c13681bff01ad59b2cc68dd838ea1f10e51574bac27103f00c91a5"}, + {file = "httpx-0.27.0.tar.gz", hash = "sha256:a0cb88a46f32dc874e04ee956e4c2764aba2aa228f650b06788ba6bda2962ab5"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" +sniffio = "*" + +[package.extras] +brotli = ["brotli", "brotlicffi"] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] + +[[package]] +name = "httpx-sse" +version = "0.4.0" +description = "Consume Server-Sent Event (SSE) messages with HTTPX." +optional = false +python-versions = ">=3.8" +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" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "iniconfig" +version = "2.0.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.7" +files = [ + {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, + {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, +] + +[[package]] +name = "mypy" +version = "1.10.0" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mypy-1.10.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:da1cbf08fb3b851ab3b9523a884c232774008267b1f83371ace57f412fe308c2"}, + {file = "mypy-1.10.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:12b6bfc1b1a66095ab413160a6e520e1dc076a28f3e22f7fb25ba3b000b4ef99"}, + {file = "mypy-1.10.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e36fb078cce9904c7989b9693e41cb9711e0600139ce3970c6ef814b6ebc2b2"}, + {file = "mypy-1.10.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2b0695d605ddcd3eb2f736cd8b4e388288c21e7de85001e9f85df9187f2b50f9"}, + {file = "mypy-1.10.0-cp310-cp310-win_amd64.whl", hash = "sha256:cd777b780312ddb135bceb9bc8722a73ec95e042f911cc279e2ec3c667076051"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3be66771aa5c97602f382230165b856c231d1277c511c9a8dd058be4784472e1"}, + {file = "mypy-1.10.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8b2cbaca148d0754a54d44121b5825ae71868c7592a53b7292eeb0f3fdae95ee"}, + {file = "mypy-1.10.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ec404a7cbe9fc0e92cb0e67f55ce0c025014e26d33e54d9e506a0f2d07fe5de"}, + {file = "mypy-1.10.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e22e1527dc3d4aa94311d246b59e47f6455b8729f4968765ac1eacf9a4760bc7"}, + {file = "mypy-1.10.0-cp311-cp311-win_amd64.whl", hash = "sha256:a87dbfa85971e8d59c9cc1fcf534efe664d8949e4c0b6b44e8ca548e746a8d53"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:a781f6ad4bab20eef8b65174a57e5203f4be627b46291f4589879bf4e257b97b"}, + {file = "mypy-1.10.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b808e12113505b97d9023b0b5e0c0705a90571c6feefc6f215c1df9381256e30"}, + {file = "mypy-1.10.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f55583b12156c399dce2df7d16f8a5095291354f1e839c252ec6c0611e86e2e"}, + {file = "mypy-1.10.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4cf18f9d0efa1b16478c4c129eabec36148032575391095f73cae2e722fcf9d5"}, + {file = "mypy-1.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:bc6ac273b23c6b82da3bb25f4136c4fd42665f17f2cd850771cb600bdd2ebeda"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9fd50226364cd2737351c79807775136b0abe084433b55b2e29181a4c3c878c0"}, + {file = "mypy-1.10.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f90cff89eea89273727d8783fef5d4a934be2fdca11b47def50cf5d311aff727"}, + {file = "mypy-1.10.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fcfc70599efde5c67862a07a1aaf50e55bce629ace26bb19dc17cece5dd31ca4"}, + {file = "mypy-1.10.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:075cbf81f3e134eadaf247de187bd604748171d6b79736fa9b6c9685b4083061"}, + {file = "mypy-1.10.0-cp38-cp38-win_amd64.whl", hash = "sha256:3f298531bca95ff615b6e9f2fc0333aae27fa48052903a0ac90215021cdcfa4f"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:fa7ef5244615a2523b56c034becde4e9e3f9b034854c93639adb667ec9ec2976"}, + {file = "mypy-1.10.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3236a4c8f535a0631f85f5fcdffba71c7feeef76a6002fcba7c1a8e57c8be1ec"}, + {file = "mypy-1.10.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a2b5cdbb5dd35aa08ea9114436e0d79aceb2f38e32c21684dcf8e24e1e92821"}, + {file = "mypy-1.10.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:92f93b21c0fe73dc00abf91022234c79d793318b8a96faac147cd579c1671746"}, + {file = "mypy-1.10.0-cp39-cp39-win_amd64.whl", hash = "sha256:28d0e038361b45f099cc086d9dd99c15ff14d0188f44ac883010e172ce86c38a"}, + {file = "mypy-1.10.0-py3-none-any.whl", hash = "sha256:f8c083976eb530019175aabadb60921e73b4f45736760826aa1689dda8208aee"}, + {file = "mypy-1.10.0.tar.gz", hash = "sha256:3d087fcbec056c4ee34974da493a826ce316947485cef3901f511848e687c131"}, +] + +[package.dependencies] +mypy-extensions = ">=1.0.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing-extensions = ">=4.1.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.0.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.5" +files = [ + {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, + {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, +] + +[[package]] +name = "orjson" +version = "3.10.3" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +files = [ + {file = "orjson-3.10.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9fb6c3f9f5490a3eb4ddd46fc1b6eadb0d6fc16fb3f07320149c3286a1409dd8"}, + {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:252124b198662eee80428f1af8c63f7ff077c88723fe206a25df8dc57a57b1fa"}, + {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9f3e87733823089a338ef9bbf363ef4de45e5c599a9bf50a7a9b82e86d0228da"}, + {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c8334c0d87103bb9fbbe59b78129f1f40d1d1e8355bbed2ca71853af15fa4ed3"}, + {file = "orjson-3.10.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1952c03439e4dce23482ac846e7961f9d4ec62086eb98ae76d97bd41d72644d7"}, + {file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c0403ed9c706dcd2809f1600ed18f4aae50be263bd7112e54b50e2c2bc3ebd6d"}, + {file = "orjson-3.10.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:382e52aa4270a037d41f325e7d1dfa395b7de0c367800b6f337d8157367bf3a7"}, + {file = "orjson-3.10.3-cp310-none-win32.whl", hash = "sha256:be2aab54313752c04f2cbaab4515291ef5af8c2256ce22abc007f89f42f49109"}, + {file = "orjson-3.10.3-cp310-none-win_amd64.whl", hash = "sha256:416b195f78ae461601893f482287cee1e3059ec49b4f99479aedf22a20b1098b"}, + {file = "orjson-3.10.3-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:73100d9abbbe730331f2242c1fc0bcb46a3ea3b4ae3348847e5a141265479700"}, + {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:544a12eee96e3ab828dbfcb4d5a0023aa971b27143a1d35dc214c176fdfb29b3"}, + {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:520de5e2ef0b4ae546bea25129d6c7c74edb43fc6cf5213f511a927f2b28148b"}, + {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ccaa0a401fc02e8828a5bedfd80f8cd389d24f65e5ca3954d72c6582495b4bcf"}, + {file = "orjson-3.10.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9a7bc9e8bc11bac40f905640acd41cbeaa87209e7e1f57ade386da658092dc16"}, + {file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:3582b34b70543a1ed6944aca75e219e1192661a63da4d039d088a09c67543b08"}, + {file = "orjson-3.10.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1c23dfa91481de880890d17aa7b91d586a4746a4c2aa9a145bebdbaf233768d5"}, + {file = "orjson-3.10.3-cp311-none-win32.whl", hash = "sha256:1770e2a0eae728b050705206d84eda8b074b65ee835e7f85c919f5705b006c9b"}, + {file = "orjson-3.10.3-cp311-none-win_amd64.whl", hash = "sha256:93433b3c1f852660eb5abdc1f4dd0ced2be031ba30900433223b28ee0140cde5"}, + {file = "orjson-3.10.3-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:a39aa73e53bec8d410875683bfa3a8edf61e5a1c7bb4014f65f81d36467ea098"}, + {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0943a96b3fa09bee1afdfccc2cb236c9c64715afa375b2af296c73d91c23eab2"}, + {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e852baafceff8da3c9defae29414cc8513a1586ad93e45f27b89a639c68e8176"}, + {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18566beb5acd76f3769c1d1a7ec06cdb81edc4d55d2765fb677e3eaa10fa99e0"}, + {file = "orjson-3.10.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1bd2218d5a3aa43060efe649ec564ebedec8ce6ae0a43654b81376216d5ebd42"}, + {file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:cf20465e74c6e17a104ecf01bf8cd3b7b252565b4ccee4548f18b012ff2f8069"}, + {file = "orjson-3.10.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ba7f67aa7f983c4345eeda16054a4677289011a478ca947cd69c0a86ea45e534"}, + {file = "orjson-3.10.3-cp312-none-win32.whl", hash = "sha256:17e0713fc159abc261eea0f4feda611d32eabc35708b74bef6ad44f6c78d5ea0"}, + {file = "orjson-3.10.3-cp312-none-win_amd64.whl", hash = "sha256:4c895383b1ec42b017dd2c75ae8a5b862fc489006afde06f14afbdd0309b2af0"}, + {file = "orjson-3.10.3-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:be2719e5041e9fb76c8c2c06b9600fe8e8584e6980061ff88dcbc2691a16d20d"}, + {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb0175a5798bdc878956099f5c54b9837cb62cfbf5d0b86ba6d77e43861bcec2"}, + {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:978be58a68ade24f1af7758626806e13cff7748a677faf95fbb298359aa1e20d"}, + {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:16bda83b5c61586f6f788333d3cf3ed19015e3b9019188c56983b5a299210eb5"}, + {file = "orjson-3.10.3-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4ad1f26bea425041e0a1adad34630c4825a9e3adec49079b1fb6ac8d36f8b754"}, + {file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:9e253498bee561fe85d6325ba55ff2ff08fb5e7184cd6a4d7754133bd19c9195"}, + {file = "orjson-3.10.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0a62f9968bab8a676a164263e485f30a0b748255ee2f4ae49a0224be95f4532b"}, + {file = "orjson-3.10.3-cp38-none-win32.whl", hash = "sha256:8d0b84403d287d4bfa9bf7d1dc298d5c1c5d9f444f3737929a66f2fe4fb8f134"}, + {file = "orjson-3.10.3-cp38-none-win_amd64.whl", hash = "sha256:8bc7a4df90da5d535e18157220d7915780d07198b54f4de0110eca6b6c11e290"}, + {file = "orjson-3.10.3-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:9059d15c30e675a58fdcd6f95465c1522b8426e092de9fff20edebfdc15e1cb0"}, + {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8d40c7f7938c9c2b934b297412c067936d0b54e4b8ab916fd1a9eb8f54c02294"}, + {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d4a654ec1de8fdaae1d80d55cee65893cb06494e124681ab335218be6a0691e7"}, + {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:831c6ef73f9aa53c5f40ae8f949ff7681b38eaddb6904aab89dca4d85099cb78"}, + {file = "orjson-3.10.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:99b880d7e34542db89f48d14ddecbd26f06838b12427d5a25d71baceb5ba119d"}, + {file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:2e5e176c994ce4bd434d7aafb9ecc893c15f347d3d2bbd8e7ce0b63071c52e25"}, + {file = "orjson-3.10.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:b69a58a37dab856491bf2d3bbf259775fdce262b727f96aafbda359cb1d114d8"}, + {file = "orjson-3.10.3-cp39-none-win32.whl", hash = "sha256:b8d4d1a6868cde356f1402c8faeb50d62cee765a1f7ffcfd6de732ab0581e063"}, + {file = "orjson-3.10.3-cp39-none-win_amd64.whl", hash = "sha256:5102f50c5fc46d94f2033fe00d392588564378260d64377aec702f21a7a22912"}, + {file = "orjson-3.10.3.tar.gz", hash = "sha256:2b166507acae7ba2f7c315dcf185a9111ad5e992ac81f2d507aac39193c2c818"}, +] + +[[package]] +name = "packaging" +version = "24.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, + {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, +] + +[[package]] +name = "pluggy" +version = "1.5.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pytest" +version = "7.4.4" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, + {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-asyncio" +version = "0.21.2" +description = "Pytest support for asyncio" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest_asyncio-0.21.2-py3-none-any.whl", hash = "sha256:ab664c88bb7998f711d8039cacd4884da6430886ae8bbd4eded552ed2004f16b"}, + {file = "pytest_asyncio-0.21.2.tar.gz", hash = "sha256:d67738fc232b94b326b9d060750beb16e0074210b98dd8b58a5239fa2a154f45"}, +] + +[package.dependencies] +pytest = ">=7.0.0" + +[package.extras] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (>=0.931)", "pytest-trio (>=0.7.0)"] + +[[package]] +name = "pytest-mock" +version = "3.14.0" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-mock-3.14.0.tar.gz", hash = "sha256:2719255a1efeceadbc056d6bf3df3d1c5015530fb40cf347c0f9afac88410bd0"}, + {file = "pytest_mock-3.14.0-py3-none-any.whl", hash = "sha256:0b72c38033392a5f4621342fe11e9219ac11ec9d375f8e2a0c164539e0d70f6f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pytest-watch" +version = "4.2.0" +description = "Local continuous test runner with pytest and watchdog." +optional = false +python-versions = "*" +files = [ + {file = "pytest-watch-4.2.0.tar.gz", hash = "sha256:06136f03d5b361718b8d0d234042f7b2f203910d8568f63df2f866b547b3d4b9"}, +] + +[package.dependencies] +colorama = ">=0.3.3" +docopt = ">=0.4.0" +pytest = ">=2.6.4" +watchdog = ">=0.6.0" + +[[package]] +name = "ruff" +version = "0.1.15" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +files = [ + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:5fe8d54df166ecc24106db7dd6a68d44852d14eb0729ea4672bb4d96c320b7df"}, + {file = "ruff-0.1.15-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:6f0bfbb53c4b4de117ac4d6ddfd33aa5fc31beeaa21d23c45c6dd249faf9126f"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e0d432aec35bfc0d800d4f70eba26e23a352386be3a6cf157083d18f6f5881c8"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:9405fa9ac0e97f35aaddf185a1be194a589424b8713e3b97b762336ec79ff807"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c66ec24fe36841636e814b8f90f572a8c0cb0e54d8b5c2d0e300d28a0d7bffec"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:6f8ad828f01e8dd32cc58bc28375150171d198491fc901f6f98d2a39ba8e3ff5"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:86811954eec63e9ea162af0ffa9f8d09088bab51b7438e8b6488b9401863c25e"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd4025ac5e87d9b80e1f300207eb2fd099ff8200fa2320d7dc066a3f4622dc6b"}, + {file = "ruff-0.1.15-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b17b93c02cdb6aeb696effecea1095ac93f3884a49a554a9afa76bb125c114c1"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:ddb87643be40f034e97e97f5bc2ef7ce39de20e34608f3f829db727a93fb82c5"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:abf4822129ed3a5ce54383d5f0e964e7fef74a41e48eb1dfad404151efc130a2"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_i686.whl", hash = "sha256:6c629cf64bacfd136c07c78ac10a54578ec9d1bd2a9d395efbee0935868bf852"}, + {file = "ruff-0.1.15-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:1bab866aafb53da39c2cadfb8e1c4550ac5340bb40300083eb8967ba25481447"}, + {file = "ruff-0.1.15-py3-none-win32.whl", hash = "sha256:2417e1cb6e2068389b07e6fa74c306b2810fe3ee3476d5b8a96616633f40d14f"}, + {file = "ruff-0.1.15-py3-none-win_amd64.whl", hash = "sha256:3837ac73d869efc4182d9036b1405ef4c73d9b1f88da2413875e34e0d6919587"}, + {file = "ruff-0.1.15-py3-none-win_arm64.whl", hash = "sha256:9a933dfb1c14ec7a33cceb1e49ec4a16b51ce3c20fd42663198746efc0427360"}, + {file = "ruff-0.1.15.tar.gz", hash = "sha256:f6dfa8c1b21c913c326919056c390966648b680966febcb796cc9d1aaab8564e"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +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 = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "typing-extensions" +version = "4.11.0" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +files = [ + {file = "typing_extensions-4.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, + {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, +] + +[[package]] +name = "watchdog" +version = "4.0.0" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:39cb34b1f1afbf23e9562501673e7146777efe95da24fab5707b88f7fb11649b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c522392acc5e962bcac3b22b9592493ffd06d1fc5d755954e6be9f4990de932b"}, + {file = "watchdog-4.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6c47bdd680009b11c9ac382163e05ca43baf4127954c5f6d0250e7d772d2b80c"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8350d4055505412a426b6ad8c521bc7d367d1637a762c70fdd93a3a0d595990b"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c17d98799f32e3f55f181f19dd2021d762eb38fdd381b4a748b9f5a36738e935"}, + {file = "watchdog-4.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4986db5e8880b0e6b7cd52ba36255d4793bf5cdc95bd6264806c233173b1ec0b"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:11e12fafb13372e18ca1bbf12d50f593e7280646687463dd47730fd4f4d5d257"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5369136a6474678e02426bd984466343924d1df8e2fd94a9b443cb7e3aa20d19"}, + {file = "watchdog-4.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:76ad8484379695f3fe46228962017a7e1337e9acadafed67eb20aabb175df98b"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:45cc09cc4c3b43fb10b59ef4d07318d9a3ecdbff03abd2e36e77b6dd9f9a5c85"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:eed82cdf79cd7f0232e2fdc1ad05b06a5e102a43e331f7d041e5f0e0a34a51c4"}, + {file = "watchdog-4.0.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ba30a896166f0fee83183cec913298151b73164160d965af2e93a20bbd2ab605"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d18d7f18a47de6863cd480734613502904611730f8def45fc52a5d97503e5101"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2895bf0518361a9728773083908801a376743bcc37dfa252b801af8fd281b1ca"}, + {file = "watchdog-4.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:87e9df830022488e235dd601478c15ad73a0389628588ba0b028cb74eb72fed8"}, + {file = "watchdog-4.0.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6e949a8a94186bced05b6508faa61b7adacc911115664ccb1923b9ad1f1ccf7b"}, + {file = "watchdog-4.0.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:6a4db54edea37d1058b08947c789a2354ee02972ed5d1e0dca9b0b820f4c7f92"}, + {file = "watchdog-4.0.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d31481ccf4694a8416b681544c23bd271f5a123162ab603c7d7d2dd7dd901a07"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_aarch64.whl", hash = "sha256:8fec441f5adcf81dd240a5fe78e3d83767999771630b5ddfc5867827a34fa3d3"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_armv7l.whl", hash = "sha256:6a9c71a0b02985b4b0b6d14b875a6c86ddea2fdbebd0c9a720a806a8bbffc69f"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_i686.whl", hash = "sha256:557ba04c816d23ce98a06e70af6abaa0485f6d94994ec78a42b05d1c03dcbd50"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64.whl", hash = "sha256:d0f9bd1fd919134d459d8abf954f63886745f4660ef66480b9d753a7c9d40927"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f9b2fdca47dc855516b2d66eef3c39f2672cbf7e7a42e7e67ad2cbfcd6ba107d"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_s390x.whl", hash = "sha256:73c7a935e62033bd5e8f0da33a4dcb763da2361921a69a5a95aaf6c93aa03a87"}, + {file = "watchdog-4.0.0-py3-none-manylinux2014_x86_64.whl", hash = "sha256:6a80d5cae8c265842c7419c560b9961561556c4361b297b4c431903f8c33b269"}, + {file = "watchdog-4.0.0-py3-none-win32.whl", hash = "sha256:8f9a542c979df62098ae9c58b19e03ad3df1c9d8c6895d96c0d51da17b243b1c"}, + {file = "watchdog-4.0.0-py3-none-win_amd64.whl", hash = "sha256:f970663fa4f7e80401a7b0cbeec00fa801bf0287d93d48368fc3e6fa32716245"}, + {file = "watchdog-4.0.0-py3-none-win_ia64.whl", hash = "sha256:9a03e16e55465177d416699331b0f3564138f1807ecc5f2de9d55d8f188d08c7"}, + {file = "watchdog-4.0.0.tar.gz", hash = "sha256:e3e7065cbdabe6183ab82199d7a4f6b3ba0a438c5a512a68559846ccb76a78ec"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[metadata] +lock-version = "2.0" +python-versions = "^3.9.0,<4.0" +content-hash = "dcd64c96c58d777998a9a0fee6e8f78153870796e294989a9b19d0e7ac10b2b7" diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml new file mode 100644 index 000000000..f6fb8ae94 --- /dev/null +++ b/libs/sdk-py/pyproject.toml @@ -0,0 +1,47 @@ +[tool.poetry] +name = "langgraph-sdk" +version = "0.1.20" +description = "" +authors = ["Nuno Campos "] +readme = "README.md" +packages = [{ include = "langgraph_sdk" }] + +[tool.poetry.dependencies] +python = "^3.9.0,<4.0" +httpx = ">=0.25.2" +httpx-sse = ">=0.4.0" +orjson = ">=3.10.1" + +[tool.poetry.group.dev.dependencies] +ruff = "^0.1.4" +codespell = "^2.2.0" +pytest = "^7.2.1" +pytest-asyncio = "^0.21.1" +pytest-mock = "^3.11.1" +pytest-watch = "^4.2.0" +mypy = "^1.10.0" + +[tool.pytest.ini_options] +# --strict-markers will raise errors on unknown marks. +# https://docs.pytest.org/en/7.1.x/how-to/mark.html#raising-errors-on-unknown-marks +# +# https://docs.pytest.org/en/7.1.x/reference/reference.html +# --strict-config any warnings encountered while parsing the `pytest` +# section of the configuration file raise errors. +addopts = "--strict-markers --strict-config --durations=5 -vv" +asyncio_mode = "auto" + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" + +[tool.ruff] +lint.select = [ + "E", # pycodestyle + "F", # Pyflakes + "UP", # pyupgrade + "B", # flake8-bugbear + "I", # isort +] +lint.ignore = ["E501", "B008", "UP007", "UP006"] From d3ab444edf85bc61a09ce718e8a4ac1af0852eba Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 20:59:12 -0400 Subject: [PATCH 02/27] CI --- .github/workflows/{lint.yml => _lint.yml} | 0 .github/workflows/{test.yml => _test.yml} | 0 .github/workflows/ci.yml | 77 +++++++++++++++++++++++ libs/cli/Makefile | 38 ++++++++--- libs/langgraph/Makefile | 2 +- libs/sdk-py/Makefile | 25 +++++--- 6 files changed, 124 insertions(+), 18 deletions(-) rename .github/workflows/{lint.yml => _lint.yml} (100%) rename .github/workflows/{test.yml => _test.yml} (100%) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/_lint.yml similarity index 100% rename from .github/workflows/lint.yml rename to .github/workflows/_lint.yml diff --git a/.github/workflows/test.yml b/.github/workflows/_test.yml similarity index 100% rename from .github/workflows/test.yml rename to .github/workflows/_test.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..b292e19d3 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,77 @@ +--- + name: CI + + on: + push: + branches: [master] + pull_request: + + # If another push to the same PR or branch happens while this workflow is still running, + # cancel the earlier run in favor of the next run. + # + # There's no point in testing an outdated version of the code. GitHub only allows + # a limited number of job runners to be active at the same time, so it's better to cancel + # pointless jobs early so that more useful jobs can run sooner. + concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + + env: + POETRY_VERSION: "1.7.1" + + jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.10' + + lint: + name: cd ${{ matrix.working-directory }} + needs: [ build ] + strategy: + matrix: + working-directory: [ + "libs/langgraph/", + "libs/sdk-py", + "libs/cli" + ] + uses: ./.github/workflows/_lint.yml + with: + working-directory: ${{ matrix.working-directory }} + secrets: inherit + + test: + name: cd ${{ matrix.working-directory }} + needs: [ build ] + strategy: + matrix: + working-directory: [ + "libs/langgraph/", + "libs/cli" + ] + uses: ./.github/workflows/_test.yml + with: + working-directory: ${{ matrix.working-directory }} + secrets: inherit + + ci_success: + name: "CI Success" + needs: [build, lint, test] + if: | + always() + runs-on: ubuntu-latest + env: + JOBS_JSON: ${{ toJSON(needs) }} + RESULTS_JSON: ${{ toJSON(needs.*.result) }} + EXIT_CODE: ${{!contains(needs.*.result, 'failure') && !contains(needs.*.result, 'cancelled') && '0' || '1'}} + steps: + - name: "CI Success" + run: | + echo $JOBS_JSON + echo $RESULTS_JSON + echo "Exiting with $EXIT_CODE" + exit $EXIT_CODE + \ No newline at end of file diff --git a/libs/cli/Makefile b/libs/cli/Makefile index 0bb0d74da..680c8f53c 100644 --- a/libs/cli/Makefile +++ b/libs/cli/Makefile @@ -1,13 +1,31 @@ -.PHONY: lint format +.PHONY: test lint format -lint: - poetry run ruff . - poetry run ruff format . --diff - poetry run mypy . - -format: - poetry run ruff format . - poetry run ruff --select I --fix . +###################### +# TESTING AND COVERAGE +###################### test: - poetry run pytest tests \ No newline at end of file + poetry run pytest tests + +###################### +# LINTING AND FORMATTING +###################### + +# Define a variable for Python and notebook files. +PYTHON_FILES=. +MYPY_CACHE=.mypy_cache +lint format: PYTHON_FILES=. +lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$') +lint_package: PYTHON_FILES=langgraph_cli +lint_tests: PYTHON_FILES=tests +lint_tests: MYPY_CACHE=.mypy_cache_test + +lint lint_diff lint_package lint_tests: + poetry run ruff . + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff --select I $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) || poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) + +format format_diff: + poetry run ruff format $(PYTHON_FILES) + poetry run ruff --select I --fix $(PYTHON_FILES) \ No newline at end of file diff --git a/libs/langgraph/Makefile b/libs/langgraph/Makefile index dad4407d2..8403fbf33 100644 --- a/libs/langgraph/Makefile +++ b/libs/langgraph/Makefile @@ -28,7 +28,7 @@ test_watch: PYTHON_FILES=. MYPY_CACHE=.mypy_cache lint format: PYTHON_FILES=. -lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --diff-filter=d master | grep -E '\.py$$|\.ipynb$$') +lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$') lint_package: PYTHON_FILES=langgraph lint_tests: PYTHON_FILES=tests lint_tests: MYPY_CACHE=.mypy_cache_test diff --git a/libs/sdk-py/Makefile b/libs/sdk-py/Makefile index d3707c2f8..f7c1fc828 100644 --- a/libs/sdk-py/Makefile +++ b/libs/sdk-py/Makefile @@ -1,10 +1,21 @@ .PHONY: lint format -lint: - poetry run ruff check . - poetry run ruff format . --diff - poetry run mypy . +###################### +# LINTING AND FORMATTING +###################### -format: - poetry run ruff format . - poetry run ruff check --select I --fix . +# Define a variable for Python and notebook files. +PYTHON_FILES=. +MYPY_CACHE=.mypy_cache +lint format: PYTHON_FILES=. +lint_diff format_diff: PYTHON_FILES=$(shell git diff --name-only --relative --diff-filter=d main . | grep -E '\.py$$|\.ipynb$$') + +lint lint_diff: + poetry run ruff . + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff format $(PYTHON_FILES) --diff + [ "$(PYTHON_FILES)" = "" ] || poetry run ruff --select I $(PYTHON_FILES) + [ "$(PYTHON_FILES)" = "" ] || mkdir -p $(MYPY_CACHE) || poetry run mypy $(PYTHON_FILES) --cache-dir $(MYPY_CACHE) + +format format_diff: + poetry run ruff format $(PYTHON_FILES) + poetry run ruff --select I --fix $(PYTHON_FILES) \ No newline at end of file From b7a67162749ccd2a2b2738f7a5f675e356ebd002 Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:20:41 -0400 Subject: [PATCH 03/27] small fixes --- .github/workflows/_lint.yml | 4 +--- .github/workflows/_test.yml | 4 +--- .github/workflows/ci.yml | 2 +- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index 5f33a0cd1..cb5035040 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -1,9 +1,7 @@ name: lint on: - push: - branches: [main] - pull_request: + workflow_call: env: POETRY_VERSION: "1.7.1" diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index f060f1a02..2fbf2076c 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -1,9 +1,7 @@ name: test on: - push: - branches: [main] - pull_request: + workflow_call: env: POETRY_VERSION: "1.7.1" diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b292e19d3..5ec781364 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,7 +3,7 @@ on: push: - branches: [master] + branches: [main] pull_request: # If another push to the same PR or branch happens while this workflow is still running, From fd5da5ec5e77a554043966af3fad83490c43e6a7 Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:34:35 -0400 Subject: [PATCH 04/27] more small fixes --- .github/workflows/_lint.yml | 14 ++++++++++++++ .github/workflows/_test.yml | 9 +++++++++ 2 files changed, 23 insertions(+) diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index cb5035040..6b5ba148d 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -2,6 +2,11 @@ name: lint on: workflow_call: + inputs: + working-directory: + required: true + type: string + description: "From which folder this pipeline executes" env: POETRY_VERSION: "1.7.1" @@ -32,14 +37,17 @@ jobs: with: python-version: ${{ matrix.python-version }} poetry-version: ${{ env.POETRY_VERSION }} + working-directory: ${{ inputs.working-directory }} cache-key: lint-with-extras - name: Check Poetry File shell: bash + working-directory: ${{ inputs.working-directory }} run: poetry check - name: Check lock file shell: bash + working-directory: ${{ inputs.working-directory }} run: poetry lock --check - name: Install dependencies @@ -51,6 +59,7 @@ jobs: # If you change this configuration, make sure to change the `cache-key` # in the `poetry_setup` action above to stop using the old cache. # It doesn't matter how you change it, any change will cause a cache-bust. + working-directory: ${{ inputs.working-directory }} run: poetry install --with test - name: Get .mypy_cache to speed up mypy @@ -58,11 +67,13 @@ jobs: env: SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2" with: + working-directory: ${{ inputs.working-directory }} path: | ./.mypy_cache key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} - name: Analysing the code with our lint + working-directory: ${{ inputs.working-directory }} run: | make lint_package @@ -75,6 +86,7 @@ jobs: # If you change this configuration, make sure to change the `cache-key` # in the `poetry_setup` action above to stop using the old cache. # It doesn't matter how you change it, any change will cause a cache-bust. + working-directory: ${{ inputs.working-directory }} run: | poetry install --with test @@ -83,9 +95,11 @@ jobs: env: SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2" with: + working-directory: ${{ inputs.working-directory }} path: ./.mypy_cache_test key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} - name: Analysing the code with our lint + working-directory: ${{ inputs.working-directory }} run: | make lint_tests diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 2fbf2076c..1dce89afa 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -2,6 +2,11 @@ name: test on: workflow_call: + inputs: + working-directory: + required: true + type: string + description: "From which folder this pipeline executes" env: POETRY_VERSION: "1.7.1" @@ -25,19 +30,23 @@ jobs: with: python-version: ${{ matrix.python-version }} poetry-version: ${{ env.POETRY_VERSION }} + working-directory: ${{ inputs.working-directory }} cache-key: core - name: Install dependencies shell: bash + working-directory: ${{ inputs.working-directory }} run: poetry install --with test - name: Run core tests shell: bash + working-directory: ${{ inputs.working-directory }} run: | make test - name: Ensure the tests did not create any additional files shell: bash + working-directory: ${{ inputs.working-directory }} run: | set -eu From c5ad863a0437b882c2d40de6dd449c877f0cc206 Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:36:06 -0400 Subject: [PATCH 05/27] even more small fixes --- .github/workflows/_lint.yml | 2 +- .github/workflows/_test.yml | 2 +- libs/langgraph/README.md | 207 ++++++++++++++++++++++++++++++++++ libs/langgraph/pyproject.toml | 2 +- 4 files changed, 210 insertions(+), 3 deletions(-) create mode 100644 libs/langgraph/README.md diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index 6b5ba148d..c596dd8c4 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -60,7 +60,7 @@ jobs: # in the `poetry_setup` action above to stop using the old cache. # It doesn't matter how you change it, any change will cause a cache-bust. working-directory: ${{ inputs.working-directory }} - run: poetry install --with test + run: poetry install --with dev - name: Get .mypy_cache to speed up mypy uses: actions/cache@v3 diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 1dce89afa..9cc81fb13 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -36,7 +36,7 @@ jobs: - name: Install dependencies shell: bash working-directory: ${{ inputs.working-directory }} - run: poetry install --with test + run: poetry install --with dev - name: Run core tests shell: bash diff --git a/libs/langgraph/README.md b/libs/langgraph/README.md new file mode 100644 index 000000000..e63722cfc --- /dev/null +++ b/libs/langgraph/README.md @@ -0,0 +1,207 @@ +# 🦜🕸️LangGraph + +![Version](https://img.shields.io/pypi/v/langgraph) +[![Downloads](https://static.pepy.tech/badge/langgraph/month)](https://pepy.tech/project/langgraph) +[![Open Issues](https://img.shields.io/github/issues-raw/langchain-ai/langgraph)](https://github.com/langchain-ai/langgraph/issues) +[![](https://dcbadge.vercel.app/api/server/6adMQxSpJS?compact=true&style=flat)](https://discord.com/channels/1038097195422978059/1170024642245832774) +[![Docs](https://img.shields.io/badge/docs-latest-blue)](https://langchain-ai.github.io/langgraph/) + +⚡ Building language agents as graphs ⚡ + +## Overview + +[LangGraph](https://langchain-ai.github.io/langgraph/) is a library for building stateful, multi-actor applications with LLMs, used to create agent and multi-agent workflows. Compared to other LLM frameworks, it offers these core benefits: cycles, controllability, and persistence. LangGraph allows you to define flows that involve cycles, essential for most agentic architectures, differentiating it from DAG-based solutions. As a very low-level framework, it provides fine-grained control over both the flow and state of your application, crucial for creating reliable agents. Additionally, LangGraph includes built-in persistence, enabling advanced human-in-the-loop and memory features. + +LangGraph is inspired by [Pregel](https://research.google/pubs/pub37252/) and [Apache Beam](https://beam.apache.org/). The public interface draws inspiration from [NetworkX](https://networkx.org/documentation/latest/). LangGraph is built by LangChain Inc, the creators of LangChain, but can be used without LangChain. + +### Key Features + +- **Cycles and Branching**: Implement loops and conditionals in your apps. +- **Persistence**: Automatically save state after each step in the graph. Pause and resume the graph execution at any point to support error recovery, human-in-the-loop workflows, time travel and more. +- **Human-in-the-Loop**: Interrupt graph execution to approve or edit next action planned by the agent. +- **Streaming Support**: Stream outputs as they are produced by each node (including token streaming). +- **Integration with LangChain**: LangGraph integrates seamlessly with [LangChain](https://github.com/langchain-ai/langchain/) and [LangSmith](https://docs.smith.langchain.com/) (but does not require them). + + +## Installation + +```shell +pip install -U langgraph +``` + +## Example + +One of the central concepts of LangGraph is state. Each graph execution creates a state that is passed between nodes in the graph as they execute, and each node updates this internal state with its return value after it executes. The way that the graph updates its internal state is defined by either the type of graph chosen or a custom function. + +Let's take a look at a simple example of an agent that can search the web using [Tavily Search API](https://tavily.com/). + +```shell +pip install langchain_openai langchain_community +``` + +```shell +export OPENAI_API_KEY=sk-... +export TAVILY_API_KEY=tvly-... +``` + +Optionally, we can set up [LangSmith](https://docs.smith.langchain.com/) for best-in-class observability. + +```shell +export LANGCHAIN_TRACING_V2="true" +export LANGCHAIN_API_KEY=ls__... +``` + +```python +from typing import Annotated, Literal, TypedDict + +from langchain_core.messages import HumanMessage +from langchain_community.tools.tavily_search import TavilySearchResults +from langchain_openai import ChatOpenAI +from langgraph.checkpoint import MemorySaver +from langgraph.graph import END, StateGraph, MessagesState +from langgraph.prebuilt import ToolNode + + +# Define the tools for the agent to use +tools = [TavilySearchResults(max_results=1)] +tool_node = ToolNode(tools) + +model = ChatOpenAI(temperature=0).bind_tools(tools) + +# Define the function that determines whether to continue or not +def should_continue(state: AgentState) -> Literal["tools", END]: + messages = state['messages'] + last_message = messages[-1] + # If the LLM makes a tool call, then we route to the "tools" node + if last_message.tool_calls: + return "tools" + # Otherwise, we stop (reply to the user) + return END + + +# Define the function that calls the model +def call_model(state: AgentState): + messages = state['messages'] + response = model.invoke(messages) + # We return a list, because this will get added to the existing list + return {"messages": [response]} + + +# Define a new graph +workflow = StateGraph(MessagesState) + +# Define the two nodes we will cycle between +workflow.add_node("agent", call_model) +workflow.add_node("tools", tool_node) + +# Set the entrypoint as `agent` +# This means that this node is the first one called +workflow.set_entry_point("agent") + +# We now add a conditional edge +workflow.add_conditional_edges( + # First, we define the start node. We use `agent`. + # This means these are the edges taken after the `agent` node is called. + "agent", + # Next, we pass in the function that will determine which node is called next. + should_continue, +) + +# We now add a normal edge from `tools` to `agent`. +# This means that after `tools` is called, `agent` node is called next. +workflow.add_edge("tools", 'agent') + +# Initialize memory to persist state between graph runs +checkpointer = MemorySaver() + +# Finally, we compile it! +# This compiles it into a LangChain Runnable, +# meaning you can use it as you would any other runnable. +# Note that we're (optionally) passing the memory when compiling the graph +app = workflow.compile(checkpointer=checkpointer) + +# Use the Runnable +final_state = app.invoke( + {"messages": [HumanMessage(content="what is the weather in sf")]}, + config={"configurable": {"thread_id": 42}} +) +final_state["messages"][-1].content +``` + +``` +'The current weather in San Francisco is as follows:\n- Temperature: 60.1°F (15.6°C)\n- Condition: Partly cloudy\n- Wind: 5.6 mph (9.0 kph) from SSW\n- Humidity: 83%\n- Visibility: 9.0 miles (16.0 km)\n- UV Index: 4.0\n\nFor more details, you can visit [Weather API](https://www.weatherapi.com/).' +``` + +Now when we pass the same `"thread_id"`, the conversation context is retained via the saved state (i.e. stored list of messages) + +```python +final_state = app.invoke( + {"messages": [HumanMessage(content="what about ny")]}, + config={"configurable": {"thread_id": 42}} +) +final_state["messages"][-1].content +``` + +``` +'The current weather in New York is as follows:\n- Temperature: 20.3°C (68.5°F)\n- Condition: Overcast\n- Wind: 2.2 mph from the north\n- Humidity: 65%\n- Cloud Cover: 100%\n- UV Index: 5.0\n\nFor more details, you can visit [Weather API](https://www.weatherapi.com/).' +``` + +### Step-by-step Breakdown: + +1.
+ Initialize the model and tools. + + - we use `ChatOpenAI` as our LLM. **NOTE:** we need make sure the model knows that it has these tools available to call. We can do this by converting the LangChain tools into the format for OpenAI tool calling using the `.bind_tools()` method. + - we define the tools we want to use -- a web search tool in our case. It is really easy to create your own tools - see documentation here on how to do that [here](https://python.langchain.com/docs/modules/agents/tools/custom_tools). +
+2.
+ Initialize graph with state. + + - we initialize graph (`StateGraph`) by passing state schema (in our case `MessagesState`) + - `MessagesState` is a prebuilt state schema that has one attribute -- a list of LangChain `Message` objects, as well as logic for merging the updates from each node into the state +
+3.
+ Define graph nodes. + + There are two main nodes we need: + - The `agent` node: responsible for deciding what (if any) actions to take. + - The `tools` node that invokes tools: if the agent decides to take an action, this node will then execute that action. +
+4.
+ Define entry point and graph edges. + + First, we need to set the entry point for graph execution - `agent` node. + + Then we define one normal and one conditional edge. Conditional edge means that the destination depends on the contents of the graph's state (`MessageState`). In our case, the destination is not known until the agent (LLM) decides. + + - Conditional edge: after the agent is called, we should either: + - a. Run tools if the agent said to take an action, OR + - b. Finish (respond to the user) if the agent did not ask to run tools + - Normal edge: after the tools are invoked, the graph should always return to the agent to decide what to do next +
+5.
+ Compile the graph. + + - When we compile the graph, we turn it into a LangChain [Runnable](https://python.langchain.com/v0.2/docs/concepts/#runnable-interface), which automatically enables calling `.invoke()`, `.stream()` and `.batch()` with your inputs + - We can also optionally pass checkpointer object for persisting state between graph runs, and enabling memory, human-in-the-loop workflows, time travel and more. In our case we use `MemorySaver` - a simple in-memory checkpointer +
+6.
+ Execute the graph. + + 1. LangGraph adds the input message to the internal state, then passes the state to the entrypoint node, `"agent"`. + 2. The `"agent"` node executes, invoking the chat model. + 3. The chat model returns an `AIMessage`. LangGraph adds this to the state. + 4. Graph cycles the following steps until there are no more `tool_calls` on `AIMessage`: + - If `AIMessage` has `tool_calls`, `"tools"` node executes + - The `"agent"` node executes again and returns `AIMessage` + 5. Execution progresses to the special `END` value and outputs the final state. + And as a result, we get a list of all our chat messages as output. +
+ + +## Documentation + +* [Tutorials](https://langchain-ai.github.io/langgraph/tutorials/): Learn to build with LangGraph through guided examples. +* [How-to Guides](https://langchain-ai.github.io/langgraph/how-tos/): Accomplish specific things within LangGraph, from streaming, to adding memory & persistence, to common design patterns (branching, subgraphs, etc.), these are the place to go if you want to copy and run a specific code snippet. +* [Conceptual Guides](https://langchain-ai.github.io/langgraph/concepts/): In-depth explanations of the key concepts and principles behind LangGraph, such as nodes, edges, state and more. +* [API Reference](https://langchain-ai.github.io/langgraph/reference/graphs/): Review important classes and methods, simple examples of how to use the graph and checkpointing APIs, higher-level prebuilt components and more. \ No newline at end of file diff --git a/libs/langgraph/pyproject.toml b/libs/langgraph/pyproject.toml index 7ff4ceb0d..39ccdf6a6 100644 --- a/libs/langgraph/pyproject.toml +++ b/libs/langgraph/pyproject.toml @@ -12,7 +12,7 @@ python = ">=3.9.0,<4.0" langchain-core = ">=0.2,<0.3" -[tool.poetry.group.test.dependencies] +[tool.poetry.group.dev.dependencies] pytest = "^7.3.0" pytest-cov = "^4.0.0" pytest-dotenv = "^0.5.2" From 8174bc22fbc62fb16895a8eaf87a1b859b959e9d Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:40:55 -0400 Subject: [PATCH 06/27] and even more small fixes --- .github/workflows/_lint.yml | 2 +- .github/workflows/link_check.yml | 2 +- .github/workflows/release.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index c596dd8c4..a84dd7f52 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -88,7 +88,7 @@ jobs: # It doesn't matter how you change it, any change will cause a cache-bust. working-directory: ${{ inputs.working-directory }} run: | - poetry install --with test + poetry install --with dev - name: Get .mypy_cache_test to speed up mypy uses: actions/cache@v3 diff --git a/.github/workflows/link_check.yml b/.github/workflows/link_check.yml index f5c02f2c9..02749a931 100644 --- a/.github/workflows/link_check.yml +++ b/.github/workflows/link_check.yml @@ -46,7 +46,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - poetry install --with test + poetry install --with dev poetry run pip install -U pytest pytest-check-links langsmith langchain GitPython # - name: Check links in notebooks diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1ce24c0df..22c70f269 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -119,7 +119,7 @@ jobs: poetry run python -c "import $IMPORT_NAME; print(dir($IMPORT_NAME))" - name: Import test dependencies - run: poetry install --with test + run: poetry install --with dev # Overwrite the local version of the package with the test PyPI version. - name: Import published package (again) From 91be8318043e78f2402de449cb0332338b798a22 Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:42:54 -0400 Subject: [PATCH 07/27] fix --- libs/langgraph/pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libs/langgraph/pyproject.toml b/libs/langgraph/pyproject.toml index 39ccdf6a6..f750b1f18 100644 --- a/libs/langgraph/pyproject.toml +++ b/libs/langgraph/pyproject.toml @@ -32,7 +32,7 @@ langchain-openai = ">=0.1.2" langchain-anthropic = ">=0.1.8" dataclasses-json = "^0.6.7" -[tool.poetry.group.test] +[tool.poetry.group.dev] optional = true [tool.ruff] From 312bd05b3aed793a37c998541974a8c663faf58e Mon Sep 17 00:00:00 2001 From: vbarda Date: Mon, 17 Jun 2024 21:44:31 -0400 Subject: [PATCH 08/27] update lock --- libs/langgraph/poetry.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/langgraph/poetry.lock b/libs/langgraph/poetry.lock index 6bf3e1244..ef758aca3 100644 --- a/libs/langgraph/poetry.lock +++ b/libs/langgraph/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "aiohttp" @@ -4122,4 +4122,4 @@ test = ["big-O", "importlib-resources", "jaraco.functools", "jaraco.itertools", [metadata] lock-version = "2.0" python-versions = ">=3.9.0,<4.0" -content-hash = "169aa0ae0415b6b959bd86040113f5f3b0f4f299eee059e46c0fcb33ba5ff0f4" +content-hash = "e4add510fb89fec1b59d54468cadbd5bff33a06c0a83e0fe923dbeb9d3d24876" From 633b444e013911c1bdd37918160c6ed207060d48 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 09:29:50 -0400 Subject: [PATCH 09/27] make the lint steps more flexible --- .github/workflows/_lint.yml | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index a84dd7f52..eb2474a18 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -72,10 +72,15 @@ jobs: ./.mypy_cache key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} - - name: Analysing the code with our lint + - name: Analysing package code with our lint working-directory: ${{ inputs.working-directory }} run: | - make lint_package + if make lint_package > /dev/null 2>&1; then + make lint_package + else + echo "lint_package command not found, skipping step" + make lint + fi - name: Install test dependencies # Also installs dev/lint/test/typing dependencies, to ensure we have @@ -99,7 +104,11 @@ jobs: path: ./.mypy_cache_test key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} - - name: Analysing the code with our lint + - name: Analysing tests with our lint working-directory: ${{ inputs.working-directory }} run: | - make lint_tests + if make lint_tests > /dev/null 2>&1; then + make lint_tests + else + echo "lint_tests command not found, skipping step" + fi From 955def04085f3297bc1bd215506e8e82f5404412 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 09:38:23 -0400 Subject: [PATCH 10/27] update caching logic + add names --- .github/workflows/_lint.yml | 14 +++++++------- .github/workflows/_test.yml | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.github/workflows/_lint.yml b/.github/workflows/_lint.yml index eb2474a18..d80d116bb 100644 --- a/.github/workflows/_lint.yml +++ b/.github/workflows/_lint.yml @@ -29,6 +29,7 @@ jobs: python-version: - "3.9" - "3.11" + name: "lint #${{ matrix.python-version }}" steps: - uses: actions/checkout@v4 @@ -67,10 +68,9 @@ jobs: env: SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2" with: - working-directory: ${{ inputs.working-directory }} path: | - ./.mypy_cache - key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} + ${{ inputs.working-directory }}/.mypy_cache + key: mypy-lint-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }} - name: Analysing package code with our lint working-directory: ${{ inputs.working-directory }} @@ -78,7 +78,7 @@ jobs: if make lint_package > /dev/null 2>&1; then make lint_package else - echo "lint_package command not found, skipping step" + echo "lint_package command not found, using lint instead" make lint fi @@ -100,9 +100,9 @@ jobs: env: SEGMENT_DOWNLOAD_TIMEOUT_MIN: "2" with: - working-directory: ${{ inputs.working-directory }} - path: ./.mypy_cache_test - key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ hashFiles('./poetry.lock') }} + path: | + ${{ inputs.working-directory }}/.mypy_cache_test + key: mypy-test-${{ runner.os }}-${{ runner.arch }}-py${{ matrix.python-version }}-${{ inputs.working-directory }}-${{ hashFiles(format('{0}/poetry.lock', inputs.working-directory)) }} - name: Analysing tests with our lint working-directory: ${{ inputs.working-directory }} diff --git a/.github/workflows/_test.yml b/.github/workflows/_test.yml index 9cc81fb13..31177dc14 100644 --- a/.github/workflows/_test.yml +++ b/.github/workflows/_test.yml @@ -21,7 +21,7 @@ jobs: - "3.10" - "3.11" - "3.12" - name: Python ${{ matrix.python-version }} + name: "test #${{ matrix.python-version }}" steps: - uses: actions/checkout@v4 From a15cab8430629d809ca9e03719834a7e7c6887ff Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 09:44:16 -0400 Subject: [PATCH 11/27] add js lint step --- .github/workflows/ci.yml | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ec781364..ab25d72b1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -57,9 +57,33 @@ working-directory: ${{ matrix.working-directory }} secrets: inherit + lint-js: + runs-on: ubuntu-latest + strategy: + matrix: + working-directory: + - "libs/sdk-js" + defaults: + run: + working-directory: ${{ matrix.working-directory }} + steps: + - uses: actions/checkout@v3 + - name: Setup Node.js (LTS) + uses: actions/setup-node@v3 + with: + node-version: "20" + cache: "yarn" + cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock + - name: Install dependencies + run: yarn install + - name: Run lint + run: yarn lint + - name: Build + run: yarn build + ci_success: name: "CI Success" - needs: [build, lint, test] + needs: [build, lint, lint-js, test] if: | always() runs-on: ubuntu-latest From 895f5f00abcea1e83a615a6c4fecc8e0f5ea21ca Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 09:57:25 -0400 Subject: [PATCH 12/27] update extract stopwords script --- .github/workflows/extract_ignored_words_list.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/extract_ignored_words_list.py b/.github/workflows/extract_ignored_words_list.py index bb949d14f..321899dd6 100644 --- a/.github/workflows/extract_ignored_words_list.py +++ b/.github/workflows/extract_ignored_words_list.py @@ -1,6 +1,6 @@ import toml -pyproject_toml = toml.load("pyproject.toml") +pyproject_toml = toml.load("libs/langgraph/pyproject.toml") # Extract the ignore words list (adjust the key as per your TOML structure) ignore_words_list = ( From ede161a0d3c7040c3b999cf05d6fe9b0cdcb846b Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 10:01:04 -0400 Subject: [PATCH 13/27] update deploy docs --- .github/workflows/deploy_docs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index a9de78976..10bd9ad9e 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -35,7 +35,7 @@ jobs: with: python-version: 3.12 cache: poetry - cache-dependency-path: "poetry.lock" + cache-dependency-path: "libs/langgraph/poetry.lock" - name: Poetry install run: | From 7d45e737fa63a8ea624780699f0867a801d2279f Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 10:17:44 -0400 Subject: [PATCH 14/27] clean up docs building --- .github/workflows/deploy_docs.yml | 24 +- .github/workflows/link_check.yml | 2 +- Makefile | 14 +- poetry.lock | 2523 +++++++++++++++++++++++++++++ pyproject.toml | 26 + 5 files changed, 2565 insertions(+), 24 deletions(-) create mode 100644 poetry.lock create mode 100644 pyproject.toml diff --git a/.github/workflows/deploy_docs.yml b/.github/workflows/deploy_docs.yml index 10bd9ad9e..29ebab7b9 100644 --- a/.github/workflows/deploy_docs.yml +++ b/.github/workflows/deploy_docs.yml @@ -9,6 +9,9 @@ on: - main workflow_dispatch: +env: + POETRY_VERSION: "1.7.1" + permissions: contents: read pages: write @@ -26,22 +29,17 @@ jobs: with: fetch-depth: 0 + - name: Set up Python + Poetry ${{ env.POETRY_VERSION }} + uses: "./.github/actions/poetry_setup" + with: + python-version: "3.12" + poetry-version: ${{ env.POETRY_VERSION }} + cache-key: docs + - name: Install dependencies run: | - pip install poetry poethepoet + poetry install --with docs - - name: Set up Python - uses: actions/setup-python@v4 - with: - python-version: 3.12 - cache: poetry - cache-dependency-path: "libs/langgraph/poetry.lock" - - - name: Poetry install - run: | - poetry install - poetry run pip install -r docs/docs-requirements.txt - - name: Build site run: make build-docs env: diff --git a/.github/workflows/link_check.yml b/.github/workflows/link_check.yml index 02749a931..34143b902 100644 --- a/.github/workflows/link_check.yml +++ b/.github/workflows/link_check.yml @@ -46,7 +46,7 @@ jobs: - name: Install dependencies run: | python -m pip install --upgrade pip - poetry install --with dev + poetry install --with docs poetry run pip install -U pytest pytest-check-links langsmith langchain GitPython # - name: Check links in notebooks diff --git a/Makefile b/Makefile index f2216a7ce..5d88e53af 100644 --- a/Makefile +++ b/Makefile @@ -1,22 +1,16 @@ -.PHONY: all clean format lint test tests test_watch integration_tests docker_tests help extended_tests coverage spell_check spell_fix build-docs serve-docs serve-clean-docs clean-docs - -spell_check: - poetry run codespell --toml pyproject.toml - -spell_fix: - poetry run codespell --toml pyproject.toml -w +.PHONY: build-docs serve-docs serve-clean-docs clean-docs build-docs: poetry run python docs/_scripts/copy_notebooks.py - poetry run mkdocs build --clean -f docs/mkdocs.yml --strict + poetry run python -m mkdocs build --clean -f docs/mkdocs.yml --strict serve-clean-docs: clean-docs poetry run python docs/_scripts/copy_notebooks.py - poetry run python -m mkdocs serve -c -f docs/mkdocs.yml --strict -w ./langgraph + poetry run python -m mkdocs serve -c -f docs/mkdocs.yml --strict -w ./libs/langgraph serve-docs: poetry run python docs/_scripts/copy_notebooks.py - poetry run python -m mkdocs serve -f docs/mkdocs.yml -w ./langgraph --dirty + poetry run python -m mkdocs serve -f docs/mkdocs.yml -w ./libs/langgraph --dirty clean-docs: find ./docs/docs -name "*.ipynb" -type f -delete diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 000000000..92ef0e1b7 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,2523 @@ +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "appnope" +version = "0.1.4" +description = "Disable App Nap on macOS >= 10.9" +optional = false +python-versions = ">=3.6" +files = [ + {file = "appnope-0.1.4-py2.py3-none-any.whl", hash = "sha256:502575ee11cd7a28c0205f379b525beefebab9d161b7c964670864014ed7213c"}, + {file = "appnope-0.1.4.tar.gz", hash = "sha256:1de3860566df9caf38f01f86f65e0e13e379af54f9e4bee1e66b48f2efffd1ee"}, +] + +[[package]] +name = "asttokens" +version = "2.4.1" +description = "Annotate AST trees with source code positions" +optional = false +python-versions = "*" +files = [ + {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, + {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, +] + +[package.dependencies] +six = ">=1.12.0" + +[package.extras] +astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] +test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] + +[[package]] +name = "attrs" +version = "23.2.0" +description = "Classes Without Boilerplate" +optional = false +python-versions = ">=3.7" +files = [ + {file = "attrs-23.2.0-py3-none-any.whl", hash = "sha256:99b87a485a5820b23b879f04c2305b44b951b502fd64be915879d77a7e8fc6f1"}, + {file = "attrs-23.2.0.tar.gz", hash = "sha256:935dc3b529c262f6cf76e50877d35a4bd3c1de194fd41f47a2b7ae8f19971f30"}, +] + +[package.extras] +cov = ["attrs[tests]", "coverage[toml] (>=5.3)"] +dev = ["attrs[tests]", "pre-commit"] +docs = ["furo", "myst-parser", "sphinx", "sphinx-notfound-page", "sphinxcontrib-towncrier", "towncrier", "zope-interface"] +tests = ["attrs[tests-no-zope]", "zope-interface"] +tests-mypy = ["mypy (>=1.6)", "pytest-mypy-plugins"] +tests-no-zope = ["attrs[tests-mypy]", "cloudpickle", "hypothesis", "pympler", "pytest (>=4.3.0)", "pytest-xdist[psutil]"] + +[[package]] +name = "babel" +version = "2.15.0" +description = "Internationalization utilities" +optional = false +python-versions = ">=3.8" +files = [ + {file = "Babel-2.15.0-py3-none-any.whl", hash = "sha256:08706bdad8d0a3413266ab61bd6c34d0c28d6e1e7badf40a2cebe67644e2e1fb"}, + {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, +] + +[package.extras] +dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] + +[[package]] +name = "beautifulsoup4" +version = "4.12.3" +description = "Screen-scraping library" +optional = false +python-versions = ">=3.6.0" +files = [ + {file = "beautifulsoup4-4.12.3-py3-none-any.whl", hash = "sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed"}, + {file = "beautifulsoup4-4.12.3.tar.gz", hash = "sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051"}, +] + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +cchardet = ["cchardet"] +chardet = ["chardet"] +charset-normalizer = ["charset-normalizer"] +html5lib = ["html5lib"] +lxml = ["lxml"] + +[[package]] +name = "bleach" +version = "6.1.0" +description = "An easy safelist-based HTML-sanitizing tool." +optional = false +python-versions = ">=3.8" +files = [ + {file = "bleach-6.1.0-py3-none-any.whl", hash = "sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6"}, + {file = "bleach-6.1.0.tar.gz", hash = "sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe"}, +] + +[package.dependencies] +six = ">=1.9.0" +webencodings = "*" + +[package.extras] +css = ["tinycss2 (>=1.1.0,<1.3)"] + +[[package]] +name = "cairocffi" +version = "1.7.1" +description = "cffi-based cairo bindings for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cairocffi-1.7.1-py3-none-any.whl", hash = "sha256:9803a0e11f6c962f3b0ae2ec8ba6ae45e957a146a004697a1ac1bbf16b073b3f"}, + {file = "cairocffi-1.7.1.tar.gz", hash = "sha256:2e48ee864884ec4a3a34bfa8c9ab9999f688286eb714a15a43ec9d068c36557b"}, +] + +[package.dependencies] +cffi = ">=1.1.0" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["numpy", "pikepdf", "pytest", "ruff"] +xcb = ["xcffib (>=1.4.0)"] + +[[package]] +name = "cairosvg" +version = "2.7.1" +description = "A Simple SVG Converter based on Cairo" +optional = false +python-versions = ">=3.5" +files = [ + {file = "CairoSVG-2.7.1-py3-none-any.whl", hash = "sha256:8a5222d4e6c3f86f1f7046b63246877a63b49923a1cd202184c3a634ef546b3b"}, + {file = "CairoSVG-2.7.1.tar.gz", hash = "sha256:432531d72347291b9a9ebfb6777026b607563fd8719c46ee742db0aef7271ba0"}, +] + +[package.dependencies] +cairocffi = "*" +cssselect2 = "*" +defusedxml = "*" +pillow = "*" +tinycss2 = "*" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "certifi" +version = "2024.6.2" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.6" +files = [ + {file = "certifi-2024.6.2-py3-none-any.whl", hash = "sha256:ddc6c8ce995e6987e7faf5e3f1b02b302836a0e5d98ece18392cb1a36c72ad56"}, + {file = "certifi-2024.6.2.tar.gz", hash = "sha256:3cd43f1c6fa7dedc5899d69d3ad0398fd018ad1a17fba83ddaf78aa46c747516"}, +] + +[[package]] +name = "cffi" +version = "1.16.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b3d6606d369fc1da4fd8c357d026317fbb9c9b75d36dc16e90e84c26854b088"}, + {file = "cffi-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ac0f5edd2360eea2f1daa9e26a41db02dd4b0451b48f7c318e217ee092a213e9"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e61e3e4fa664a8588aa25c883eab612a188c725755afff6289454d6362b9673"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a72e8961a86d19bdb45851d8f1f08b041ea37d2bd8d4fd19903bc3083d80c896"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5b50bf3f55561dac5438f8e70bfcdfd74543fd60df5fa5f62d94e5867deca684"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7651c50c8c5ef7bdb41108b7b8c5a83013bfaa8a935590c5d74627c047a583c7"}, + {file = "cffi-1.16.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4108df7fe9b707191e55f33efbcb2d81928e10cea45527879a4749cbe472614"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:32c68ef735dbe5857c810328cb2481e24722a59a2003018885514d4c09af9743"}, + {file = "cffi-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:673739cb539f8cdaa07d92d02efa93c9ccf87e345b9a0b556e3ecc666718468d"}, + {file = "cffi-1.16.0-cp310-cp310-win32.whl", hash = "sha256:9f90389693731ff1f659e55c7d1640e2ec43ff725cc61b04b2f9c6d8d017df6a"}, + {file = "cffi-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:e6024675e67af929088fda399b2094574609396b1decb609c55fa58b028a32a1"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b84834d0cf97e7d27dd5b7f3aca7b6e9263c56308ab9dc8aae9784abb774d404"}, + {file = "cffi-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1b8ebc27c014c59692bb2664c7d13ce7a6e9a629be20e54e7271fa696ff2b417"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee07e47c12890ef248766a6e55bd38ebfb2bb8edd4142d56db91b21ea68b7627"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8a9d3ebe49f084ad71f9269834ceccbf398253c9fac910c4fd7053ff1386936"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e70f54f1796669ef691ca07d046cd81a29cb4deb1e5f942003f401c0c4a2695d"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf44d66cdf9e893637896c7faa22298baebcd18d1ddb6d2626a6e39793a1d56"}, + {file = "cffi-1.16.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7b78010e7b97fef4bee1e896df8a4bbb6712b7f05b7ef630f9d1da00f6444d2e"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c6a164aa47843fb1b01e941d385aab7215563bb8816d80ff3a363a9f8448a8dc"}, + {file = "cffi-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e09f3ff613345df5e8c3667da1d918f9149bd623cd9070c983c013792a9a62eb"}, + {file = "cffi-1.16.0-cp311-cp311-win32.whl", hash = "sha256:2c56b361916f390cd758a57f2e16233eb4f64bcbeee88a4881ea90fca14dc6ab"}, + {file = "cffi-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:db8e577c19c0fda0beb7e0d4e09e0ba74b1e4c092e0e40bfa12fe05b6f6d75ba"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:fa3a0128b152627161ce47201262d3140edb5a5c3da88d73a1b790a959126956"}, + {file = "cffi-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68e7c44931cc171c54ccb702482e9fc723192e88d25a0e133edd7aff8fcd1f6e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:abd808f9c129ba2beda4cfc53bde801e5bcf9d6e0f22f095e45327c038bfe68e"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88e2b3c14bdb32e440be531ade29d3c50a1a59cd4e51b1dd8b0865c54ea5d2e2"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcc8eb6d5902bb1cf6dc4f187ee3ea80a1eba0a89aba40a5cb20a5087d961357"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b7be2d771cdba2942e13215c4e340bfd76398e9227ad10402a8767ab1865d2e6"}, + {file = "cffi-1.16.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e715596e683d2ce000574bae5d07bd522c781a822866c20495e52520564f0969"}, + {file = "cffi-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2d92b25dbf6cae33f65005baf472d2c245c050b1ce709cc4588cdcdd5495b520"}, + {file = "cffi-1.16.0-cp312-cp312-win32.whl", hash = "sha256:b2ca4e77f9f47c55c194982e10f058db063937845bb2b7a86c84a6cfe0aefa8b"}, + {file = "cffi-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:68678abf380b42ce21a5f2abde8efee05c114c2fdb2e9eef2efdb0257fba1235"}, + {file = "cffi-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:0c9ef6ff37e974b73c25eecc13952c55bceed9112be2d9d938ded8e856138bcc"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a09582f178759ee8128d9270cd1344154fd473bb77d94ce0aeb2a93ebf0feaf0"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e760191dd42581e023a68b758769e2da259b5d52e3103c6060ddc02c9edb8d7b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:80876338e19c951fdfed6198e70bc88f1c9758b94578d5a7c4c91a87af3cf31c"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a6a14b17d7e17fa0d207ac08642c8820f84f25ce17a442fd15e27ea18d67c59b"}, + {file = "cffi-1.16.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6602bc8dc6f3a9e02b6c22c4fc1e47aa50f8f8e6d3f78a5e16ac33ef5fefa324"}, + {file = "cffi-1.16.0-cp38-cp38-win32.whl", hash = "sha256:131fd094d1065b19540c3d72594260f118b231090295d8c34e19a7bbcf2e860a"}, + {file = "cffi-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:31d13b0f99e0836b7ff893d37af07366ebc90b678b6664c955b54561fc36ef36"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:582215a0e9adbe0e379761260553ba11c58943e4bbe9c36430c4ca6ac74b15ed"}, + {file = "cffi-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:b29ebffcf550f9da55bec9e02ad430c992a87e5f512cd63388abb76f1036d8d2"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc9b18bf40cc75f66f40a7379f6a9513244fe33c0e8aa72e2d56b0196a7ef872"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cb4a35b3642fc5c005a6755a5d17c6c8b6bcb6981baf81cea8bfbc8903e8ba8"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b86851a328eedc692acf81fb05444bdf1891747c25af7529e39ddafaf68a4f3f"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c0f31130ebc2d37cdd8e44605fb5fa7ad59049298b3f745c74fa74c62fbfcfc4"}, + {file = "cffi-1.16.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f8e709127c6c77446a8c0a8c8bf3c8ee706a06cd44b1e827c3e6a2ee6b8c098"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:748dcd1e3d3d7cd5443ef03ce8685043294ad6bd7c02a38d1bd367cfd968e000"}, + {file = "cffi-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:8895613bcc094d4a1b2dbe179d88d7fb4a15cee43c052e8885783fac397d91fe"}, + {file = "cffi-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed86a35631f7bfbb28e108dd96773b9d5a6ce4811cf6ea468bb6a359b256b1e4"}, + {file = "cffi-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:3686dffb02459559c74dd3d81748269ffb0eb027c39a6fc99502de37d501faa8"}, + {file = "cffi-1.16.0.tar.gz", hash = "sha256:bcb3ef43e58665bbda2fb198698fcae6776483e0c4a631aa5647806c25e02cc0"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "charset-normalizer" +version = "3.3.2" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, + {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, + {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, + {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, + {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, + {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, + {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, + {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +] + +[[package]] +name = "click" +version = "8.1.7" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.7" +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" +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 = "comm" +version = "0.2.2" +description = "Jupyter Python Comm implementation, for usage in ipykernel, xeus-python etc." +optional = false +python-versions = ">=3.8" +files = [ + {file = "comm-0.2.2-py3-none-any.whl", hash = "sha256:e6fb86cb70ff661ee8c9c14e7d36d6de3b4066f1441be4063df9c5009f0a64d3"}, + {file = "comm-0.2.2.tar.gz", hash = "sha256:3fd7a84065306e07bea1773df6eb8282de51ba82f77c72f9c85716ab11fe980e"}, +] + +[package.dependencies] +traitlets = ">=4" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "csscompressor" +version = "0.9.5" +description = "A python port of YUI CSS Compressor" +optional = false +python-versions = "*" +files = [ + {file = "csscompressor-0.9.5.tar.gz", hash = "sha256:afa22badbcf3120a4f392e4d22f9fff485c044a1feda4a950ecc5eba9dd31a05"}, +] + +[[package]] +name = "cssselect2" +version = "0.7.0" +description = "CSS selectors for Python ElementTree" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cssselect2-0.7.0-py3-none-any.whl", hash = "sha256:fd23a65bfd444595913f02fc71f6b286c29261e354c41d722ca7a261a49b5969"}, + {file = "cssselect2-0.7.0.tar.gz", hash = "sha256:1ccd984dab89fc68955043aca4e1b03e0cf29cad9880f6e28e3ba7a74b14aa5a"}, +] + +[package.dependencies] +tinycss2 = "*" +webencodings = "*" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["flake8", "isort", "pytest"] + +[[package]] +name = "debugpy" +version = "1.8.1" +description = "An implementation of the Debug Adapter Protocol for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, + {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, + {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, + {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, + {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, + {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, + {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, + {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, + {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, + {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, + {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, + {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, + {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, + {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, + {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, + {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, + {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, + {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, + {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, + {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, + {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, + {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, +] + +[[package]] +name = "decorator" +version = "5.1.1" +description = "Decorators for Humans" +optional = false +python-versions = ">=3.5" +files = [ + {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, + {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, +] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.2.1" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +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 = "executing" +version = "2.0.1" +description = "Get the currently executing AST node of a frame, and other information" +optional = false +python-versions = ">=3.5" +files = [ + {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, + {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, +] + +[package.extras] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] + +[[package]] +name = "fastjsonschema" +version = "2.20.0" +description = "Fastest Python implementation of JSON schema" +optional = false +python-versions = "*" +files = [ + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "ghp-import" +version = "2.1.0" +description = "Copy your docs directly to the gh-pages branch." +optional = false +python-versions = "*" +files = [ + {file = "ghp-import-2.1.0.tar.gz", hash = "sha256:9c535c4c61193c2df8871222567d7fd7e5014d835f97dc7b7439069e2413d343"}, + {file = "ghp_import-2.1.0-py3-none-any.whl", hash = "sha256:8337dd7b50877f163d4c0289bc1f1c7f127550241988d568c1db512c4324a619"}, +] + +[package.dependencies] +python-dateutil = ">=2.8.1" + +[package.extras] +dev = ["flake8", "markdown", "twine", "wheel"] + +[[package]] +name = "gitdb" +version = "4.0.11" +description = "Git Object Database" +optional = false +python-versions = ">=3.7" +files = [ + {file = "gitdb-4.0.11-py3-none-any.whl", hash = "sha256:81a3407ddd2ee8df444cbacea00e2d038e40150acfa3001696fe0dcf1d3adfa4"}, + {file = "gitdb-4.0.11.tar.gz", hash = "sha256:bf5421126136d6d0af55bc1e7c1af1c397a34f5b7bd79e776cd3e89785c2b04b"}, +] + +[package.dependencies] +smmap = ">=3.0.1,<6" + +[[package]] +name = "gitpython" +version = "3.1.43" +description = "GitPython is a Python library used to interact with Git repositories" +optional = false +python-versions = ">=3.7" +files = [ + {file = "GitPython-3.1.43-py3-none-any.whl", hash = "sha256:eec7ec56b92aad751f9912a73404bc02ba212a23adb2c7098ee668417051a1ff"}, + {file = "GitPython-3.1.43.tar.gz", hash = "sha256:35f314a9f878467f5453cc1fee295c3e18e52f1b99f10f6cf5b1682e968a9e7c"}, +] + +[package.dependencies] +gitdb = ">=4.0.1,<5" + +[package.extras] +doc = ["sphinx (==4.3.2)", "sphinx-autodoc-typehints", "sphinx-rtd-theme", "sphinxcontrib-applehelp (>=1.0.2,<=1.0.4)", "sphinxcontrib-devhelp (==1.0.2)", "sphinxcontrib-htmlhelp (>=2.0.0,<=2.0.1)", "sphinxcontrib-qthelp (==1.0.3)", "sphinxcontrib-serializinghtml (==1.1.5)"] +test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock", "mypy", "pre-commit", "pytest (>=7.3.1)", "pytest-cov", "pytest-instafail", "pytest-mock", "pytest-sugar", "typing-extensions"] + +[[package]] +name = "griffe" +version = "0.47.0" +description = "Signatures for entire Python programs. Extract the structure, the frame, the skeleton of your project, to generate API documentation or find breaking changes in your API." +optional = false +python-versions = ">=3.8" +files = [ + {file = "griffe-0.47.0-py3-none-any.whl", hash = "sha256:07a2fd6a8c3d21d0bbb0decf701d62042ccc8a576645c7f8799fe1f10de2b2de"}, + {file = "griffe-0.47.0.tar.gz", hash = "sha256:95119a440a3c932b13293538bdbc405bee4c36428547553dc6b327e7e7d35e5a"}, +] + +[package.dependencies] +colorama = ">=0.4" + +[[package]] +name = "htmlmin2" +version = "0.1.13" +description = "An HTML Minifier" +optional = false +python-versions = "*" +files = [ + {file = "htmlmin2-0.1.13-py3-none-any.whl", hash = "sha256:75609f2a42e64f7ce57dbff28a39890363bde9e7e5885db633317efbdf8c79a2"}, +] + +[[package]] +name = "idna" +version = "3.7" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.5" +files = [ + {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, + {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, +] + +[[package]] +name = "ipykernel" +version = "6.29.4" +description = "IPython Kernel for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "ipykernel-6.29.4-py3-none-any.whl", hash = "sha256:1181e653d95c6808039c509ef8e67c4126b3b3af7781496c7cbfb5ed938a27da"}, + {file = "ipykernel-6.29.4.tar.gz", hash = "sha256:3d44070060f9475ac2092b760123fadf105d2e2493c24848b6691a7c4f42af5c"}, +] + +[package.dependencies] +appnope = {version = "*", markers = "platform_system == \"Darwin\""} +comm = ">=0.1.1" +debugpy = ">=1.6.5" +ipython = ">=7.23.1" +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +matplotlib-inline = ">=0.1" +nest-asyncio = "*" +packaging = "*" +psutil = "*" +pyzmq = ">=24" +tornado = ">=6.1" +traitlets = ">=5.4.0" + +[package.extras] +cov = ["coverage[toml]", "curio", "matplotlib", "pytest-cov", "trio"] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "trio"] +pyqt5 = ["pyqt5"] +pyside6 = ["pyside6"] +test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio (>=0.23.5)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "ipython" +version = "8.25.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +files = [ + {file = "ipython-8.25.0-py3-none-any.whl", hash = "sha256:53eee7ad44df903a06655871cbab66d156a051fd86f3ec6750470ac9604ac1ab"}, + {file = "ipython-8.25.0.tar.gz", hash = "sha256:c6ed726a140b6e725b911528f80439c534fac915246af3efc39440a6b0f9d716"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt-toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack-data = "*" +traitlets = ">=5.13.0" +typing-extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx-registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli", "typing-extensions"] +kernel = ["ipykernel"] +matplotlib = ["matplotlib"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + +[[package]] +name = "jedi" +version = "0.19.1" +description = "An autocompletion tool for Python that can be used for text editors." +optional = false +python-versions = ">=3.6" +files = [ + {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, + {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, +] + +[package.dependencies] +parso = ">=0.8.3,<0.9.0" + +[package.extras] +docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] + +[[package]] +name = "jinja2" +version = "3.1.4" +description = "A very fast and expressive template engine." +optional = false +python-versions = ">=3.7" +files = [ + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, +] + +[package.dependencies] +MarkupSafe = ">=2.0" + +[package.extras] +i18n = ["Babel (>=2.7)"] + +[[package]] +name = "jsmin" +version = "3.0.1" +description = "JavaScript minifier." +optional = false +python-versions = "*" +files = [ + {file = "jsmin-3.0.1.tar.gz", hash = "sha256:c0959a121ef94542e807a674142606f7e90214a2b3d1eb17300244bbb5cc2bfc"}, +] + +[[package]] +name = "jsonpatch" +version = "1.33" +description = "Apply JSON-Patches (RFC 6902)" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*, !=3.6.*" +files = [ + {file = "jsonpatch-1.33-py2.py3-none-any.whl", hash = "sha256:0ae28c0cd062bbd8b8ecc26d7d164fbbea9652a1a3693f3b956c1eae5145dade"}, + {file = "jsonpatch-1.33.tar.gz", hash = "sha256:9fcd4009c41e6d12348b4a0ff2563ba56a2923a7dfee731d004e212e1ee5030c"}, +] + +[package.dependencies] +jsonpointer = ">=1.9" + +[[package]] +name = "jsonpointer" +version = "3.0.0" +description = "Identify specific nodes in a JSON document (RFC 6901)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jsonpointer-3.0.0-py2.py3-none-any.whl", hash = "sha256:13e088adc14fca8b6aa8177c044e12701e6ad4b28ff10e65f2267a90109c9942"}, + {file = "jsonpointer-3.0.0.tar.gz", hash = "sha256:2b2d729f2091522d61c3b31f82e11870f60b68f43fbc705cb76bf4b832af59ef"}, +] + +[[package]] +name = "jsonschema" +version = "4.22.0" +description = "An implementation of JSON Schema validation for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema-4.22.0-py3-none-any.whl", hash = "sha256:ff4cfd6b1367a40e7bc6411caec72effadd3db0bbe5017de188f2d6108335802"}, + {file = "jsonschema-4.22.0.tar.gz", hash = "sha256:5b22d434a45935119af990552c862e5d6d564e8f6601206b305a61fdf661a2b7"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +jsonschema-specifications = ">=2023.03.6" +referencing = ">=0.28.4" +rpds-py = ">=0.7.1" + +[package.extras] +format = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3987", "uri-template", "webcolors (>=1.11)"] +format-nongpl = ["fqdn", "idna", "isoduration", "jsonpointer (>1.13)", "rfc3339-validator", "rfc3986-validator (>0.1.0)", "uri-template", "webcolors (>=1.11)"] + +[[package]] +name = "jsonschema-specifications" +version = "2023.12.1" +description = "The JSON Schema meta-schemas and vocabularies, exposed as a Registry" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jsonschema_specifications-2023.12.1-py3-none-any.whl", hash = "sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c"}, + {file = "jsonschema_specifications-2023.12.1.tar.gz", hash = "sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc"}, +] + +[package.dependencies] +referencing = ">=0.31.0" + +[[package]] +name = "jupyter-client" +version = "8.6.2" +description = "Jupyter protocol implementation and client libraries" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_client-8.6.2-py3-none-any.whl", hash = "sha256:50cbc5c66fd1b8f65ecb66bc490ab73217993632809b6e505687de18e9dea39f"}, + {file = "jupyter_client-8.6.2.tar.gz", hash = "sha256:2bda14d55ee5ba58552a8c53ae43d215ad9868853489213f37da060ced54d8df"}, +] + +[package.dependencies] +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +python-dateutil = ">=2.8.2" +pyzmq = ">=23.0" +tornado = ">=6.2" +traitlets = ">=5.3" + +[package.extras] +docs = ["ipykernel", "myst-parser", "pydata-sphinx-theme", "sphinx (>=4)", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["coverage", "ipykernel (>=6.14)", "mypy", "paramiko", "pre-commit", "pytest (<8.2.0)", "pytest-cov", "pytest-jupyter[client] (>=0.4.1)", "pytest-timeout"] + +[[package]] +name = "jupyter-core" +version = "5.7.2" +description = "Jupyter core package. A base package on which Jupyter projects rely." +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyter_core-5.7.2-py3-none-any.whl", hash = "sha256:4f7315d2f6b4bcf2e3e7cb6e46772eba760ae459cd1f59d29eb57b0a01bd7409"}, + {file = "jupyter_core-5.7.2.tar.gz", hash = "sha256:aa5f8d32bbf6b431ac830496da7392035d6f61b4f54872f15c4bd2a9c3f536d9"}, +] + +[package.dependencies] +platformdirs = ">=2.5" +pywin32 = {version = ">=300", markers = "sys_platform == \"win32\" and platform_python_implementation != \"PyPy\""} +traitlets = ">=5.3" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx-autodoc-typehints", "sphinxcontrib-github-alt", "sphinxcontrib-spelling", "traitlets"] +test = ["ipykernel", "pre-commit", "pytest (<8)", "pytest-cov", "pytest-timeout"] + +[[package]] +name = "jupyterlab-pygments" +version = "0.3.0" +description = "Pygments theme using JupyterLab CSS variables" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupyterlab_pygments-0.3.0-py3-none-any.whl", hash = "sha256:841a89020971da1d8693f1a99997aefc5dc424bb1b251fd6322462a1b8842780"}, + {file = "jupyterlab_pygments-0.3.0.tar.gz", hash = "sha256:721aca4d9029252b11cfa9d185e5b5af4d54772bb8072f9b7036f4170054d35d"}, +] + +[[package]] +name = "jupytext" +version = "1.16.2" +description = "Jupyter notebooks as Markdown documents, Julia, Python or R scripts" +optional = false +python-versions = ">=3.8" +files = [ + {file = "jupytext-1.16.2-py3-none-any.whl", hash = "sha256:197a43fef31dca612b68b311e01b8abd54441c7e637810b16b6cb8f2ab66065e"}, + {file = "jupytext-1.16.2.tar.gz", hash = "sha256:8627dd9becbbebd79cc4a4ed4727d89d78e606b4b464eab72357b3b029023a14"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0" +mdit-py-plugins = "*" +nbformat = "*" +packaging = "*" +pyyaml = "*" +tomli = {version = "*", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] +docs = ["myst-parser", "sphinx", "sphinx-copybutton", "sphinx-rtd-theme"] +test = ["pytest", "pytest-randomly", "pytest-xdist"] +test-cov = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-cov (>=2.6.1)", "pytest-randomly", "pytest-xdist"] +test-external = ["autopep8", "black", "flake8", "gitpython", "ipykernel", "isort", "jupyter-fs (<0.4.0)", "jupyter-server (!=2.11)", "nbconvert", "pre-commit", "pytest", "pytest-randomly", "pytest-xdist", "sphinx-gallery (<0.8)"] +test-functional = ["pytest", "pytest-randomly", "pytest-xdist"] +test-integration = ["ipykernel", "jupyter-server (!=2.11)", "nbconvert", "pytest", "pytest-randomly", "pytest-xdist"] +test-ui = ["calysto-bash"] + +[[package]] +name = "langchain-core" +version = "0.2.8" +description = "Building applications with LLMs through composability" +optional = false +python-versions = "<4.0,>=3.8.1" +files = [ + {file = "langchain_core-0.2.8-py3-none-any.whl", hash = "sha256:172c81c858dc1f3123cc72b7e44e10f44c92f8a761cae18c364081f6c208e9f6"}, + {file = "langchain_core-0.2.8.tar.gz", hash = "sha256:2db866a4514672c4875b69d5590aa2ed50aa0d144874268bef68d74b5e7f33f9"}, +] + +[package.dependencies] +jsonpatch = ">=1.33,<2.0" +langsmith = ">=0.1.75,<0.2.0" +packaging = ">=23.2,<25" +pydantic = ">=1,<3" +PyYAML = ">=5.3" +tenacity = ">=8.1.0,<9.0.0" + +[[package]] +name = "langgraph" +version = "0.0.69" +description = "langgraph" +optional = false +python-versions = ">=3.9.0,<4.0" +files = [] +develop = true + +[package.dependencies] +langchain-core = ">=0.2,<0.3" + +[package.source] +type = "directory" +url = "libs/langgraph" + +[[package]] +name = "langsmith" +version = "0.1.79" +description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." +optional = false +python-versions = "<4.0,>=3.8.1" +files = [ + {file = "langsmith-0.1.79-py3-none-any.whl", hash = "sha256:c7f2c23981917713b5515b773f37c84ff68a7adf803476e2ebb5adcb36a04202"}, + {file = "langsmith-0.1.79.tar.gz", hash = "sha256:d215718cfdcdf4a011126b7a3d4a37eee96d887e59ac1e628a57e24b2bfa3163"}, +] + +[package.dependencies] +orjson = ">=3.9.14,<4.0.0" +pydantic = ">=1,<3" +requests = ">=2,<3" + +[[package]] +name = "markdown" +version = "3.6" +description = "Python implementation of John Gruber's Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "Markdown-3.6-py3-none-any.whl", hash = "sha256:48f276f4d8cfb8ce6527c8f79e2ee29708508bf4d40aa410fbc3b4ee832c850f"}, + {file = "Markdown-3.6.tar.gz", hash = "sha256:ed4f41f6daecbeeb96e576ce414c41d2d876daa9a16cb35fa8ed8c2ddfad0224"}, +] + +[package.extras] +docs = ["mdx-gh-links (>=0.2)", "mkdocs (>=1.5)", "mkdocs-gen-files", "mkdocs-literate-nav", "mkdocs-nature (>=0.6)", "mkdocs-section-index", "mkdocstrings[python]"] +testing = ["coverage", "pyyaml"] + +[[package]] +name = "markdown-it-py" +version = "3.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.8" +files = [ + {file = "markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb"}, + {file = "markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +code-style = ["pre-commit (>=3.0,<4.0)"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "mistletoe (>=1.0,<2.0)", "mistune (>=2.0,<3.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins"] +profiling = ["gprof2dot"] +rtd = ["jupyter_sphinx", "mdit-py-plugins", "myst-parser", "pyyaml", "sphinx", "sphinx-copybutton", "sphinx-design", "sphinx_book_theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "markupsafe" +version = "2.1.5" +description = "Safely add untrusted strings to HTML/XML markup." +optional = false +python-versions = ">=3.7" +files = [ + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, + {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, + {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, + {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, + {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, + {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, + {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, + {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +] + +[[package]] +name = "matplotlib-inline" +version = "0.1.7" +description = "Inline Matplotlib backend for Jupyter" +optional = false +python-versions = ">=3.8" +files = [ + {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, + {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, +] + +[package.dependencies] +traitlets = "*" + +[[package]] +name = "mdit-py-plugins" +version = "0.4.1" +description = "Collection of plugins for markdown-it-py" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mdit_py_plugins-0.4.1-py3-none-any.whl", hash = "sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a"}, + {file = "mdit_py_plugins-0.4.1.tar.gz", hash = "sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c"}, +] + +[package.dependencies] +markdown-it-py = ">=1.0.0,<4.0.0" + +[package.extras] +code-style = ["pre-commit"] +rtd = ["myst-parser", "sphinx-book-theme"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "mergedeep" +version = "1.3.4" +description = "A deep merge function for 🐍." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mergedeep-1.3.4-py3-none-any.whl", hash = "sha256:70775750742b25c0d8f36c55aed03d24c3384d17c951b3175d898bd778ef0307"}, + {file = "mergedeep-1.3.4.tar.gz", hash = "sha256:0096d52e9dad9939c3d975a774666af186eda617e6ca84df4c94dec30004f2a8"}, +] + +[[package]] +name = "mistune" +version = "3.0.2" +description = "A sane and fast Markdown parser with useful plugins and renderers" +optional = false +python-versions = ">=3.7" +files = [ + {file = "mistune-3.0.2-py3-none-any.whl", hash = "sha256:71481854c30fdbc938963d3605b72501f5c10a9320ecd412c121c163a1c7d205"}, + {file = "mistune-3.0.2.tar.gz", hash = "sha256:fc7f93ded930c92394ef2cb6f04a8aabab4117a91449e72dcc8dfa646a508be8"}, +] + +[[package]] +name = "mkdocs" +version = "1.6.0" +description = "Project documentation with Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-1.6.0-py3-none-any.whl", hash = "sha256:1eb5cb7676b7d89323e62b56235010216319217d4af5ddc543a91beb8d125ea7"}, + {file = "mkdocs-1.6.0.tar.gz", hash = "sha256:a73f735824ef83a4f3bcb7a231dcab23f5a838f88b7efc54a0eef5fbdbc3c512"}, +] + +[package.dependencies] +click = ">=7.0" +colorama = {version = ">=0.4", markers = "platform_system == \"Windows\""} +ghp-import = ">=1.0" +jinja2 = ">=2.11.1" +markdown = ">=3.3.6" +markupsafe = ">=2.0.1" +mergedeep = ">=1.3.4" +mkdocs-get-deps = ">=0.2.0" +packaging = ">=20.5" +pathspec = ">=0.11.1" +pyyaml = ">=5.1" +pyyaml-env-tag = ">=0.1" +watchdog = ">=2.0" + +[package.extras] +i18n = ["babel (>=2.9.0)"] +min-versions = ["babel (==2.9.0)", "click (==7.0)", "colorama (==0.4)", "ghp-import (==1.0)", "importlib-metadata (==4.4)", "jinja2 (==2.11.1)", "markdown (==3.3.6)", "markupsafe (==2.0.1)", "mergedeep (==1.3.4)", "mkdocs-get-deps (==0.2.0)", "packaging (==20.5)", "pathspec (==0.11.1)", "pyyaml (==5.1)", "pyyaml-env-tag (==0.1)", "watchdog (==2.0)"] + +[[package]] +name = "mkdocs-autorefs" +version = "1.0.1" +description = "Automatically link across pages in MkDocs." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_autorefs-1.0.1-py3-none-any.whl", hash = "sha256:aacdfae1ab197780fb7a2dac92ad8a3d8f7ca8049a9cbe56a4218cd52e8da570"}, + {file = "mkdocs_autorefs-1.0.1.tar.gz", hash = "sha256:f684edf847eced40b570b57846b15f0bf57fb93ac2c510450775dcf16accb971"}, +] + +[package.dependencies] +Markdown = ">=3.3" +markupsafe = ">=2.0.1" +mkdocs = ">=1.1" + +[[package]] +name = "mkdocs-get-deps" +version = "0.2.0" +description = "MkDocs extension that lists all dependencies according to a mkdocs.yml file" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_get_deps-0.2.0-py3-none-any.whl", hash = "sha256:2bf11d0b133e77a0dd036abeeb06dec8775e46efa526dc70667d8863eefc6134"}, + {file = "mkdocs_get_deps-0.2.0.tar.gz", hash = "sha256:162b3d129c7fad9b19abfdcb9c1458a651628e4b1dea628ac68790fb3061c60c"}, +] + +[package.dependencies] +mergedeep = ">=1.3.4" +platformdirs = ">=2.2.0" +pyyaml = ">=5.1" + +[[package]] +name = "mkdocs-git-committers-plugin-2" +version = "2.3.0" +description = "An MkDocs plugin to create a list of contributors on the page. The git-committers plugin will seed the template context with a list of GitHub or GitLab committers and other useful GIT info such as last modified date" +optional = false +python-versions = ">=3.8,<4" +files = [ + {file = "mkdocs-git-committers-plugin-2-2.3.0.tar.gz", hash = "sha256:d6baca1ae04db8120640038eda8142f2d081c27b53f3b566c83c75717e4ed81a"}, + {file = "mkdocs_git_committers_plugin_2-2.3.0-py3-none-any.whl", hash = "sha256:7b3434af3be525c12858eb3b44b4c6b695b7c7b7760482ea8de1c6e292e84f0f"}, +] + +[package.dependencies] +gitpython = "*" +mkdocs = ">=1.0.3" +requests = "*" + +[[package]] +name = "mkdocs-jupyter" +version = "0.24.7" +description = "Use Jupyter in mkdocs websites" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_jupyter-0.24.7-py3-none-any.whl", hash = "sha256:893d04bea1e007479a46e4e72852cd4d280c4d358ce4a0445250f3f80c639723"}, +] + +[package.dependencies] +ipykernel = ">6.0.0,<7.0.0" +jupytext = ">1.13.8,<2" +mkdocs = ">=1.4.0,<2" +mkdocs-material = ">9.0.0" +nbconvert = ">=7.2.9,<8" +pygments = ">2.12.0" + +[[package]] +name = "mkdocs-material" +version = "9.5.27" +description = "Documentation that simply works" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material-9.5.27-py3-none-any.whl", hash = "sha256:af8cc263fafa98bb79e9e15a8c966204abf15164987569bd1175fd66a7705182"}, + {file = "mkdocs_material-9.5.27.tar.gz", hash = "sha256:a7d4a35f6d4a62b0c43a0cfe7e987da0980c13587b5bc3c26e690ad494427ec0"}, +] + +[package.dependencies] +babel = ">=2.10,<3.0" +cairosvg = {version = ">=2.6,<3.0", optional = true, markers = "extra == \"imaging\""} +colorama = ">=0.4,<1.0" +jinja2 = ">=3.0,<4.0" +markdown = ">=3.2,<4.0" +mkdocs = ">=1.6,<2.0" +mkdocs-material-extensions = ">=1.3,<2.0" +paginate = ">=0.5,<1.0" +pillow = {version = ">=10.2,<11.0", optional = true, markers = "extra == \"imaging\""} +pygments = ">=2.16,<3.0" +pymdown-extensions = ">=10.2,<11.0" +regex = ">=2022.4" +requests = ">=2.26,<3.0" + +[package.extras] +git = ["mkdocs-git-committers-plugin-2 (>=1.1,<2.0)", "mkdocs-git-revision-date-localized-plugin (>=1.2.4,<2.0)"] +imaging = ["cairosvg (>=2.6,<3.0)", "pillow (>=10.2,<11.0)"] +recommended = ["mkdocs-minify-plugin (>=0.7,<1.0)", "mkdocs-redirects (>=1.2,<2.0)", "mkdocs-rss-plugin (>=1.6,<2.0)"] + +[[package]] +name = "mkdocs-material-extensions" +version = "1.3.1" +description = "Extension pack for Python Markdown and MkDocs Material." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs_material_extensions-1.3.1-py3-none-any.whl", hash = "sha256:adff8b62700b25cb77b53358dad940f3ef973dd6db797907c49e3c2ef3ab4e31"}, + {file = "mkdocs_material_extensions-1.3.1.tar.gz", hash = "sha256:10c9511cea88f568257f960358a467d12b970e1f7b2c0e5fb2bb48cab1928443"}, +] + +[[package]] +name = "mkdocs-minify-plugin" +version = "0.8.0" +description = "An MkDocs plugin to minify HTML, JS or CSS files prior to being written to disk" +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocs-minify-plugin-0.8.0.tar.gz", hash = "sha256:bc11b78b8120d79e817308e2b11539d790d21445eb63df831e393f76e52e753d"}, + {file = "mkdocs_minify_plugin-0.8.0-py3-none-any.whl", hash = "sha256:5fba1a3f7bd9a2142c9954a6559a57e946587b21f133165ece30ea145c66aee6"}, +] + +[package.dependencies] +csscompressor = ">=0.9.5" +htmlmin2 = ">=0.1.13" +jsmin = ">=3.0.1" +mkdocs = ">=1.4.1" + +[[package]] +name = "mkdocs-redirects" +version = "1.2.1" +description = "A MkDocs plugin for dynamic page redirects to prevent broken links." +optional = false +python-versions = ">=3.6" +files = [ + {file = "mkdocs-redirects-1.2.1.tar.gz", hash = "sha256:9420066d70e2a6bb357adf86e67023dcdca1857f97f07c7fe450f8f1fb42f861"}, + {file = "mkdocs_redirects-1.2.1-py3-none-any.whl", hash = "sha256:497089f9e0219e7389304cffefccdfa1cac5ff9509f2cb706f4c9b221726dffb"}, +] + +[package.dependencies] +mkdocs = ">=1.1.1" + +[package.extras] +dev = ["autoflake", "black", "isort", "pytest", "twine (>=1.13.0)"] +release = ["twine (>=1.13.0)"] +test = ["autoflake", "black", "isort", "pytest"] + +[[package]] +name = "mkdocs-rss-plugin" +version = "1.13.1" +description = "MkDocs plugin which generates a static RSS feed using git log and page.meta." +optional = false +python-versions = "<4,>=3.10" +files = [ + {file = "mkdocs_rss_plugin-1.13.1-py2.py3-none-any.whl", hash = "sha256:665af194d0a48a1a88f3753c3cee78fee8e00b269dd61af1fe79f3555457b7a4"}, + {file = "mkdocs_rss_plugin-1.13.1.tar.gz", hash = "sha256:1c12b1a7449dcff686b8fd991648a88bb8735e5013242b10ff4f375b90a93803"}, +] + +[package.dependencies] +GitPython = ">=3.1,<3.2" +mkdocs = ">=1.5,<2" +requests = ">=2.31,<3" +tzdata = {version = "==2024.*", markers = "python_version >= \"3.9\" and sys_platform == \"win32\""} + +[package.extras] +dev = ["black", "flake8 (>=6,<8)", "flake8-bugbear (>=23.12)", "flake8-builtins (>=2.1)", "flake8-eradicate (>=1)", "flake8-isort (>=6)", "pre-commit (>=3,<4)"] +doc = ["mkdocs-git-committers-plugin-2 (>=1.2,<2.4)", "mkdocs-git-revision-date-localized-plugin (>=1,<1.3)", "mkdocs-material[imaging] (>=9.5.1,<10)", "mkdocs-minify-plugin (==0.8.*)", "mkdocstrings[python] (>=0.18,<1)", "termynal (>=0.11.1,<0.13)"] +test = ["feedparser (>=6.0.11,<6.1)", "jsonfeed-util (>=1.1.2,<2)", "mkdocs-material[imaging] (>=9)", "pytest-cov (>=4,<5.1)", "validator-collection (>=1.5,<1.6)"] + +[[package]] +name = "mkdocstrings" +version = "0.25.1" +description = "Automatic documentation from sources, for MkDocs." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocstrings-0.25.1-py3-none-any.whl", hash = "sha256:da01fcc2670ad61888e8fe5b60afe9fee5781017d67431996832d63e887c2e51"}, + {file = "mkdocstrings-0.25.1.tar.gz", hash = "sha256:c3a2515f31577f311a9ee58d089e4c51fc6046dbd9e9b4c3de4c3194667fe9bf"}, +] + +[package.dependencies] +click = ">=7.0" +Jinja2 = ">=2.11.1" +Markdown = ">=3.3" +MarkupSafe = ">=1.1" +mkdocs = ">=1.4" +mkdocs-autorefs = ">=0.3.1" +platformdirs = ">=2.2.0" +pymdown-extensions = ">=6.3" + +[package.extras] +crystal = ["mkdocstrings-crystal (>=0.3.4)"] +python = ["mkdocstrings-python (>=0.5.2)"] +python-legacy = ["mkdocstrings-python-legacy (>=0.2.1)"] + +[[package]] +name = "mkdocstrings-python" +version = "1.10.4" +description = "A Python handler for mkdocstrings." +optional = false +python-versions = ">=3.8" +files = [ + {file = "mkdocstrings_python-1.10.4-py3-none-any.whl", hash = "sha256:55141806a463fedad0d8d405088612aaea7efa518aa24d4a6227021775c44369"}, + {file = "mkdocstrings_python-1.10.4.tar.gz", hash = "sha256:629a7d8bdd38358275dd44078bfc560f85e62ad3f244816b04783f30c4e2fea0"}, +] + +[package.dependencies] +griffe = ">=0.47" +mkdocstrings = ">=0.25" + +[[package]] +name = "nbclient" +version = "0.10.0" +description = "A client library for executing notebooks. Formerly nbconvert's ExecutePreprocessor." +optional = false +python-versions = ">=3.8.0" +files = [ + {file = "nbclient-0.10.0-py3-none-any.whl", hash = "sha256:f13e3529332a1f1f81d82a53210322476a168bb7090a0289c795fe9cc11c9d3f"}, + {file = "nbclient-0.10.0.tar.gz", hash = "sha256:4b3f1b7dba531e498449c4db4f53da339c91d449dc11e9af3a43b4eb5c5abb09"}, +] + +[package.dependencies] +jupyter-client = ">=6.1.12" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +nbformat = ">=5.1" +traitlets = ">=5.4" + +[package.extras] +dev = ["pre-commit"] +docs = ["autodoc-traits", "mock", "moto", "myst-parser", "nbclient[test]", "sphinx (>=1.7)", "sphinx-book-theme", "sphinxcontrib-spelling"] +test = ["flaky", "ipykernel (>=6.19.3)", "ipython", "ipywidgets", "nbconvert (>=7.0.0)", "pytest (>=7.0,<8)", "pytest-asyncio", "pytest-cov (>=4.0)", "testpath", "xmltodict"] + +[[package]] +name = "nbconvert" +version = "7.16.4" +description = "Converting Jupyter Notebooks (.ipynb files) to other formats. Output formats include asciidoc, html, latex, markdown, pdf, py, rst, script. nbconvert can be used both as a Python library (`import nbconvert`) or as a command line tool (invoked as `jupyter nbconvert ...`)." +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbconvert-7.16.4-py3-none-any.whl", hash = "sha256:05873c620fe520b6322bf8a5ad562692343fe3452abda5765c7a34b7d1aa3eb3"}, + {file = "nbconvert-7.16.4.tar.gz", hash = "sha256:86ca91ba266b0a448dc96fa6c5b9d98affabde2867b363258703536807f9f7f4"}, +] + +[package.dependencies] +beautifulsoup4 = "*" +bleach = "!=5.0.0" +defusedxml = "*" +jinja2 = ">=3.0" +jupyter-core = ">=4.7" +jupyterlab-pygments = "*" +markupsafe = ">=2.0" +mistune = ">=2.0.3,<4" +nbclient = ">=0.5.0" +nbformat = ">=5.7" +packaging = "*" +pandocfilters = ">=1.4.1" +pygments = ">=2.4.1" +tinycss2 = "*" +traitlets = ">=5.1" + +[package.extras] +all = ["flaky", "ipykernel", "ipython", "ipywidgets (>=7.5)", "myst-parser", "nbsphinx (>=0.2.12)", "playwright", "pydata-sphinx-theme", "pyqtwebengine (>=5.15)", "pytest (>=7)", "sphinx (==5.0.2)", "sphinxcontrib-spelling", "tornado (>=6.1)"] +docs = ["ipykernel", "ipython", "myst-parser", "nbsphinx (>=0.2.12)", "pydata-sphinx-theme", "sphinx (==5.0.2)", "sphinxcontrib-spelling"] +qtpdf = ["pyqtwebengine (>=5.15)"] +qtpng = ["pyqtwebengine (>=5.15)"] +serve = ["tornado (>=6.1)"] +test = ["flaky", "ipykernel", "ipywidgets (>=7.5)", "pytest (>=7)"] +webpdf = ["playwright"] + +[[package]] +name = "nbformat" +version = "5.10.4" +description = "The Jupyter Notebook format" +optional = false +python-versions = ">=3.8" +files = [ + {file = "nbformat-5.10.4-py3-none-any.whl", hash = "sha256:3b48d6c8fbca4b299bf3982ea7db1af21580e4fec269ad087b9e81588891200b"}, + {file = "nbformat-5.10.4.tar.gz", hash = "sha256:322168b14f937a5d11362988ecac2a4952d3d8e3a2cbeb2319584631226d5b3a"}, +] + +[package.dependencies] +fastjsonschema = ">=2.15" +jsonschema = ">=2.6" +jupyter-core = ">=4.12,<5.0.dev0 || >=5.1.dev0" +traitlets = ">=5.1" + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx", "sphinxcontrib-github-alt", "sphinxcontrib-spelling"] +test = ["pep440", "pre-commit", "pytest", "testpath"] + +[[package]] +name = "nest-asyncio" +version = "1.6.0" +description = "Patch asyncio to allow nested event loops" +optional = false +python-versions = ">=3.5" +files = [ + {file = "nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c"}, + {file = "nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe"}, +] + +[[package]] +name = "orjson" +version = "3.10.5" +description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" +optional = false +python-versions = ">=3.8" +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 = "packaging" +version = "24.1" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +files = [ + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, +] + +[[package]] +name = "paginate" +version = "0.5.6" +description = "Divides large result sets into pages for easier browsing" +optional = false +python-versions = "*" +files = [ + {file = "paginate-0.5.6.tar.gz", hash = "sha256:5e6007b6a9398177a7e1648d04fdd9f8c9766a1a945bceac82f1929e8c78af2d"}, +] + +[[package]] +name = "pandocfilters" +version = "1.5.1" +description = "Utilities for writing pandoc filters in python" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pandocfilters-1.5.1-py2.py3-none-any.whl", hash = "sha256:93be382804a9cdb0a7267585f157e5d1731bbe5545a85b268d6f5fe6232de2bc"}, + {file = "pandocfilters-1.5.1.tar.gz", hash = "sha256:002b4a555ee4ebc03f8b66307e287fa492e4a77b4ea14d3f934328297bb4939e"}, +] + +[[package]] +name = "parso" +version = "0.8.4" +description = "A Python Parser" +optional = false +python-versions = ">=3.6" +files = [ + {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, + {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, +] + +[package.extras] +qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] +testing = ["docopt", "pytest"] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pexpect" +version = "4.9.0" +description = "Pexpect allows easy control of interactive console applications." +optional = false +python-versions = "*" +files = [ + {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, + {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, +] + +[package.dependencies] +ptyprocess = ">=0.5" + +[[package]] +name = "pillow" +version = "10.3.0" +description = "Python Imaging Library (Fork)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pillow-10.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:90b9e29824800e90c84e4022dd5cc16eb2d9605ee13f05d47641eb183cd73d45"}, + {file = "pillow-10.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a2c405445c79c3f5a124573a051062300936b0281fee57637e706453e452746c"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78618cdbccaa74d3f88d0ad6cb8ac3007f1a6fa5c6f19af64b55ca170bfa1edf"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:261ddb7ca91fcf71757979534fb4c128448b5b4c55cb6152d280312062f69599"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:ce49c67f4ea0609933d01c0731b34b8695a7a748d6c8d186f95e7d085d2fe475"}, + {file = "pillow-10.3.0-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:b14f16f94cbc61215115b9b1236f9c18403c15dd3c52cf629072afa9d54c1cbf"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d33891be6df59d93df4d846640f0e46f1a807339f09e79a8040bc887bdcd7ed3"}, + {file = "pillow-10.3.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:b50811d664d392f02f7761621303eba9d1b056fb1868c8cdf4231279645c25f5"}, + {file = "pillow-10.3.0-cp310-cp310-win32.whl", hash = "sha256:ca2870d5d10d8726a27396d3ca4cf7976cec0f3cb706debe88e3a5bd4610f7d2"}, + {file = "pillow-10.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f"}, + {file = "pillow-10.3.0-cp310-cp310-win_arm64.whl", hash = "sha256:ccce24b7ad89adb5a1e34a6ba96ac2530046763912806ad4c247356a8f33a67b"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_10_10_x86_64.whl", hash = "sha256:5f77cf66e96ae734717d341c145c5949c63180842a545c47a0ce7ae52ca83795"}, + {file = "pillow-10.3.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e4b878386c4bf293578b48fc570b84ecfe477d3b77ba39a6e87150af77f40c57"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9797a6c8fe16f25749b371c02e2ade0efb51155e767a971c61734b1bf6293994"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:9e91179a242bbc99be65e139e30690e081fe6cb91a8e77faf4c409653de39451"}, + {file = "pillow-10.3.0-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:1b87bd9d81d179bd8ab871603bd80d8645729939f90b71e62914e816a76fc6bd"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:81d09caa7b27ef4e61cb7d8fbf1714f5aec1c6b6c5270ee53504981e6e9121ad"}, + {file = "pillow-10.3.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:048ad577748b9fa4a99a0548c64f2cb8d672d5bf2e643a739ac8faff1164238c"}, + {file = "pillow-10.3.0-cp311-cp311-win32.whl", hash = "sha256:7161ec49ef0800947dc5570f86568a7bb36fa97dd09e9827dc02b718c5643f09"}, + {file = "pillow-10.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:8eb0908e954d093b02a543dc963984d6e99ad2b5e36503d8a0aaf040505f747d"}, + {file = "pillow-10.3.0-cp311-cp311-win_arm64.whl", hash = "sha256:4e6f7d1c414191c1199f8996d3f2282b9ebea0945693fb67392c75a3a320941f"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_10_10_x86_64.whl", hash = "sha256:e46f38133e5a060d46bd630faa4d9fa0202377495df1f068a8299fd78c84de84"}, + {file = "pillow-10.3.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:50b8eae8f7334ec826d6eeffaeeb00e36b5e24aa0b9df322c247539714c6df19"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d3bea1c75f8c53ee4d505c3e67d8c158ad4df0d83170605b50b64025917f338"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:19aeb96d43902f0a783946a0a87dbdad5c84c936025b8419da0a0cd7724356b1"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:74d28c17412d9caa1066f7a31df8403ec23d5268ba46cd0ad2c50fb82ae40462"}, + {file = "pillow-10.3.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d886f5d353333b4771d21267c7ecc75b710f1a73d72d03ca06df49b09015a9ef"}, + {file = "pillow-10.3.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4b5ec25d8b17217d635f8935dbc1b9aa5907962fae29dff220f2659487891cd3"}, + {file = "pillow-10.3.0-cp312-cp312-win32.whl", hash = "sha256:51243f1ed5161b9945011a7360e997729776f6e5d7005ba0c6879267d4c5139d"}, + {file = "pillow-10.3.0-cp312-cp312-win_amd64.whl", hash = "sha256:412444afb8c4c7a6cc11a47dade32982439925537e483be7c0ae0cf96c4f6a0b"}, + {file = "pillow-10.3.0-cp312-cp312-win_arm64.whl", hash = "sha256:798232c92e7665fe82ac085f9d8e8ca98826f8e27859d9a96b41d519ecd2e49a"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_10_10_x86_64.whl", hash = "sha256:4eaa22f0d22b1a7e93ff0a596d57fdede2e550aecffb5a1ef1106aaece48e96b"}, + {file = "pillow-10.3.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cd5e14fbf22a87321b24c88669aad3a51ec052eb145315b3da3b7e3cc105b9a2"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1530e8f3a4b965eb6a7785cf17a426c779333eb62c9a7d1bbcf3ffd5bf77a4aa"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d512aafa1d32efa014fa041d38868fda85028e3f930a96f85d49c7d8ddc0383"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_aarch64.whl", hash = "sha256:339894035d0ede518b16073bdc2feef4c991ee991a29774b33e515f1d308e08d"}, + {file = "pillow-10.3.0-cp38-cp38-manylinux_2_28_x86_64.whl", hash = "sha256:aa7e402ce11f0885305bfb6afb3434b3cd8f53b563ac065452d9d5654c7b86fd"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:0ea2a783a2bdf2a561808fe4a7a12e9aa3799b701ba305de596bc48b8bdfce9d"}, + {file = "pillow-10.3.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:c78e1b00a87ce43bb37642c0812315b411e856a905d58d597750eb79802aaaa3"}, + {file = "pillow-10.3.0-cp38-cp38-win32.whl", hash = "sha256:72d622d262e463dfb7595202d229f5f3ab4b852289a1cd09650362db23b9eb0b"}, + {file = "pillow-10.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:2034f6759a722da3a3dbd91a81148cf884e91d1b747992ca288ab88c1de15999"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_10_10_x86_64.whl", hash = "sha256:2ed854e716a89b1afcedea551cd85f2eb2a807613752ab997b9974aaa0d56936"}, + {file = "pillow-10.3.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:dc1a390a82755a8c26c9964d457d4c9cbec5405896cba94cf51f36ea0d855002"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4203efca580f0dd6f882ca211f923168548f7ba334c189e9eab1178ab840bf60"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3102045a10945173d38336f6e71a8dc71bcaeed55c3123ad4af82c52807b9375"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6fb1b30043271ec92dc65f6d9f0b7a830c210b8a96423074b15c7bc999975f57"}, + {file = "pillow-10.3.0-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:1dfc94946bc60ea375cc39cff0b8da6c7e5f8fcdc1d946beb8da5c216156ddd8"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b09b86b27a064c9624d0a6c54da01c1beaf5b6cadfa609cf63789b1d08a797b9"}, + {file = "pillow-10.3.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d3b2348a78bc939b4fed6552abfd2e7988e0f81443ef3911a4b8498ca084f6eb"}, + {file = "pillow-10.3.0-cp39-cp39-win32.whl", hash = "sha256:45ebc7b45406febf07fef35d856f0293a92e7417ae7933207e90bf9090b70572"}, + {file = "pillow-10.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:0ba26351b137ca4e0db0342d5d00d2e355eb29372c05afd544ebf47c0956ffeb"}, + {file = "pillow-10.3.0-cp39-cp39-win_arm64.whl", hash = "sha256:50fd3f6b26e3441ae07b7c979309638b72abc1a25da31a81a7fbd9495713ef4f"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_10_10_x86_64.whl", hash = "sha256:6b02471b72526ab8a18c39cb7967b72d194ec53c1fd0a70b050565a0f366d355"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:8ab74c06ffdab957d7670c2a5a6e1a70181cd10b727cd788c4dd9005b6a8acd9"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:048eeade4c33fdf7e08da40ef402e748df113fd0b4584e32c4af74fe78baaeb2"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2ec1e921fd07c7cda7962bad283acc2f2a9ccc1b971ee4b216b75fad6f0463"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:4c8e73e99da7db1b4cad7f8d682cf6abad7844da39834c288fbfa394a47bbced"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:16563993329b79513f59142a6b02055e10514c1a8e86dca8b48a893e33cf91e3"}, + {file = "pillow-10.3.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:dd78700f5788ae180b5ee8902c6aea5a5726bac7c364b202b4b3e3ba2d293170"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_10_10_x86_64.whl", hash = "sha256:aff76a55a8aa8364d25400a210a65ff59d0168e0b4285ba6bf2bd83cf675ba32"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b7bc2176354defba3edc2b9a777744462da2f8e921fbaf61e52acb95bafa9828"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:793b4e24db2e8742ca6423d3fde8396db336698c55cd34b660663ee9e45ed37f"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d93480005693d247f8346bc8ee28c72a2191bdf1f6b5db469c096c0c867ac015"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c83341b89884e2b2e55886e8fbbf37c3fa5efd6c8907124aeb72f285ae5696e5"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1a1d1915db1a4fdb2754b9de292642a39a7fb28f1736699527bb649484fb966a"}, + {file = "pillow-10.3.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:a0eaa93d054751ee9964afa21c06247779b90440ca41d184aeb5d410f20ff591"}, + {file = "pillow-10.3.0.tar.gz", hash = "sha256:9d2455fbf44c914840c793e89aa82d0e1763a14253a000743719ae5946814b2d"}, +] + +[package.extras] +docs = ["furo", "olefile", "sphinx (>=2.4)", "sphinx-copybutton", "sphinx-inline-tabs", "sphinx-removed-in", "sphinxext-opengraph"] +fpx = ["olefile"] +mic = ["olefile"] +tests = ["check-manifest", "coverage", "defusedxml", "markdown2", "olefile", "packaging", "pyroma", "pytest", "pytest-cov", "pytest-timeout"] +typing = ["typing-extensions"] +xmp = ["defusedxml"] + +[[package]] +name = "platformdirs" +version = "4.2.2" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.8" +files = [ + {file = "platformdirs-4.2.2-py3-none-any.whl", hash = "sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee"}, + {file = "platformdirs-4.2.2.tar.gz", hash = "sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3"}, +] + +[package.extras] +docs = ["furo (>=2023.9.10)", "proselint (>=0.13)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)"] +type = ["mypy (>=1.8)"] + +[[package]] +name = "prompt-toolkit" +version = "3.0.47" +description = "Library for building powerful interactive command lines in Python" +optional = false +python-versions = ">=3.7.0" +files = [ + {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, + {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, +] + +[package.dependencies] +wcwidth = "*" + +[[package]] +name = "psutil" +version = "5.9.8" +description = "Cross-platform lib for process and system monitoring in Python." +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +files = [ + {file = "psutil-5.9.8-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:26bd09967ae00920df88e0352a91cff1a78f8d69b3ecabbfe733610c0af486c8"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_i686.whl", hash = "sha256:05806de88103b25903dff19bb6692bd2e714ccf9e668d050d144012055cbca73"}, + {file = "psutil-5.9.8-cp27-cp27m-manylinux2010_x86_64.whl", hash = "sha256:611052c4bc70432ec770d5d54f64206aa7203a101ec273a0cd82418c86503bb7"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_i686.whl", hash = "sha256:50187900d73c1381ba1454cf40308c2bf6f34268518b3f36a9b663ca87e65e36"}, + {file = "psutil-5.9.8-cp27-cp27mu-manylinux2010_x86_64.whl", hash = "sha256:02615ed8c5ea222323408ceba16c60e99c3f91639b07da6373fb7e6539abc56d"}, + {file = "psutil-5.9.8-cp27-none-win32.whl", hash = "sha256:36f435891adb138ed3c9e58c6af3e2e6ca9ac2f365efe1f9cfef2794e6c93b4e"}, + {file = "psutil-5.9.8-cp27-none-win_amd64.whl", hash = "sha256:bd1184ceb3f87651a67b2708d4c3338e9b10c5df903f2e3776b62303b26cb631"}, + {file = "psutil-5.9.8-cp36-abi3-macosx_10_9_x86_64.whl", hash = "sha256:aee678c8720623dc456fa20659af736241f575d79429a0e5e9cf88ae0605cc81"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cb6403ce6d8e047495a701dc7c5bd788add903f8986d523e3e20b98b733e421"}, + {file = "psutil-5.9.8-cp36-abi3-manylinux_2_12_x86_64.manylinux2010_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d06016f7f8625a1825ba3732081d77c94589dca78b7a3fc072194851e88461a4"}, + {file = "psutil-5.9.8-cp36-cp36m-win32.whl", hash = "sha256:7d79560ad97af658a0f6adfef8b834b53f64746d45b403f225b85c5c2c140eee"}, + {file = "psutil-5.9.8-cp36-cp36m-win_amd64.whl", hash = "sha256:27cc40c3493bb10de1be4b3f07cae4c010ce715290a5be22b98493509c6299e2"}, + {file = "psutil-5.9.8-cp37-abi3-win32.whl", hash = "sha256:bc56c2a1b0d15aa3eaa5a60c9f3f8e3e565303b465dbf57a1b730e7a2b9844e0"}, + {file = "psutil-5.9.8-cp37-abi3-win_amd64.whl", hash = "sha256:8db4c1b57507eef143a15a6884ca10f7c73876cdf5d51e713151c1236a0e68cf"}, + {file = "psutil-5.9.8-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:d16bbddf0693323b8c6123dd804100241da461e41d6e332fb0ba6058f630f8c8"}, + {file = "psutil-5.9.8.tar.gz", hash = "sha256:6be126e3225486dff286a8fb9a06246a5253f4c7c53b475ea5f5ac934e64194c"}, +] + +[package.extras] +test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] + +[[package]] +name = "ptyprocess" +version = "0.7.0" +description = "Run a subprocess in a pseudo terminal" +optional = false +python-versions = "*" +files = [ + {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, + {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, +] + +[[package]] +name = "pure-eval" +version = "0.2.2" +description = "Safely evaluate AST nodes without side effects" +optional = false +python-versions = "*" +files = [ + {file = "pure_eval-0.2.2-py3-none-any.whl", hash = "sha256:01eaab343580944bc56080ebe0a674b39ec44a945e6d09ba7db3cb8cec289350"}, + {file = "pure_eval-0.2.2.tar.gz", hash = "sha256:2b45320af6dfaa1750f543d714b6d1c520a1688dec6fd24d339063ce0aaa9ac3"}, +] + +[package.extras] +tests = ["pytest"] + +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + +[[package]] +name = "pydantic" +version = "2.7.4" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, + {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, +] + +[package.dependencies] +annotated-types = ">=0.4.0" +pydantic-core = "2.18.4" +typing-extensions = ">=4.6.1" + +[package.extras] +email = ["email-validator (>=2.0.0)"] + +[[package]] +name = "pydantic-core" +version = "2.18.4" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.8" +files = [ + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:f76d0ad001edd426b92233d45c746fd08f467d56100fd8f30e9ace4b005266e4"}, + {file = "pydantic_core-2.18.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:59ff3e89f4eaf14050c8022011862df275b552caef8082e37b542b066ce1ff26"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a55b5b16c839df1070bc113c1f7f94a0af4433fcfa1b41799ce7606e5c79ce0a"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4d0dcc59664fcb8974b356fe0a18a672d6d7cf9f54746c05f43275fc48636851"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8951eee36c57cd128f779e641e21eb40bc5073eb28b2d23f33eb0ef14ffb3f5d"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4701b19f7e3a06ea655513f7938de6f108123bf7c86bbebb1196eb9bd35cf724"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e00a3f196329e08e43d99b79b286d60ce46bed10f2280d25a1718399457e06be"}, + {file = "pydantic_core-2.18.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:97736815b9cc893b2b7f663628e63f436018b75f44854c8027040e05230eeddb"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:6891a2ae0e8692679c07728819b6e2b822fb30ca7445f67bbf6509b25a96332c"}, + {file = "pydantic_core-2.18.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bc4ff9805858bd54d1a20efff925ccd89c9d2e7cf4986144b30802bf78091c3e"}, + {file = "pydantic_core-2.18.4-cp310-none-win32.whl", hash = "sha256:1b4de2e51bbcb61fdebd0ab86ef28062704f62c82bbf4addc4e37fa4b00b7cbc"}, + {file = "pydantic_core-2.18.4-cp310-none-win_amd64.whl", hash = "sha256:6a750aec7bf431517a9fd78cb93c97b9b0c496090fee84a47a0d23668976b4b0"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:942ba11e7dfb66dc70f9ae66b33452f51ac7bb90676da39a7345e99ffb55402d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b2ebef0e0b4454320274f5e83a41844c63438fdc874ea40a8b5b4ecb7693f1c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a642295cd0c8df1b86fc3dced1d067874c353a188dc8e0f744626d49e9aa51c4"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f09baa656c904807e832cf9cce799c6460c450c4ad80803517032da0cd062e2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:98906207f29bc2c459ff64fa007afd10a8c8ac080f7e4d5beff4c97086a3dabd"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19894b95aacfa98e7cb093cd7881a0c76f55731efad31073db4521e2b6ff5b7d"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0fbbdc827fe5e42e4d196c746b890b3d72876bdbf160b0eafe9f0334525119c8"}, + {file = "pydantic_core-2.18.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f85d05aa0918283cf29a30b547b4df2fbb56b45b135f9e35b6807cb28bc47951"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e85637bc8fe81ddb73fda9e56bab24560bdddfa98aa64f87aaa4e4b6730c23d2"}, + {file = "pydantic_core-2.18.4-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2f5966897e5461f818e136b8451d0551a2e77259eb0f73a837027b47dc95dab9"}, + {file = "pydantic_core-2.18.4-cp311-none-win32.whl", hash = "sha256:44c7486a4228413c317952e9d89598bcdfb06399735e49e0f8df643e1ccd0558"}, + {file = "pydantic_core-2.18.4-cp311-none-win_amd64.whl", hash = "sha256:8a7164fe2005d03c64fd3b85649891cd4953a8de53107940bf272500ba8a788b"}, + {file = "pydantic_core-2.18.4-cp311-none-win_arm64.whl", hash = "sha256:4e99bc050fe65c450344421017f98298a97cefc18c53bb2f7b3531eb39bc7805"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:6f5c4d41b2771c730ea1c34e458e781b18cc668d194958e0112455fff4e402b2"}, + {file = "pydantic_core-2.18.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:2fdf2156aa3d017fddf8aea5adfba9f777db1d6022d392b682d2a8329e087cef"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4748321b5078216070b151d5271ef3e7cc905ab170bbfd27d5c83ee3ec436695"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:847a35c4d58721c5dc3dba599878ebbdfd96784f3fb8bb2c356e123bdcd73f34"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c40d4eaad41f78e3bbda31b89edc46a3f3dc6e171bf0ecf097ff7a0ffff7cb1"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:21a5e440dbe315ab9825fcd459b8814bb92b27c974cbc23c3e8baa2b76890077"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:01dd777215e2aa86dfd664daed5957704b769e726626393438f9c87690ce78c3"}, + {file = "pydantic_core-2.18.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b06beb3b3f1479d32befd1f3079cc47b34fa2da62457cdf6c963393340b56e9"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:564d7922e4b13a16b98772441879fcdcbe82ff50daa622d681dd682175ea918c"}, + {file = "pydantic_core-2.18.4-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:0eb2a4f660fcd8e2b1c90ad566db2b98d7f3f4717c64fe0a83e0adb39766d5b8"}, + {file = "pydantic_core-2.18.4-cp312-none-win32.whl", hash = "sha256:8b8bab4c97248095ae0c4455b5a1cd1cdd96e4e4769306ab19dda135ea4cdb07"}, + {file = "pydantic_core-2.18.4-cp312-none-win_amd64.whl", hash = "sha256:14601cdb733d741b8958224030e2bfe21a4a881fb3dd6fbb21f071cabd48fa0a"}, + {file = "pydantic_core-2.18.4-cp312-none-win_arm64.whl", hash = "sha256:c1322d7dd74713dcc157a2b7898a564ab091ca6c58302d5c7b4c07296e3fd00f"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:823be1deb01793da05ecb0484d6c9e20baebb39bd42b5d72636ae9cf8350dbd2"}, + {file = "pydantic_core-2.18.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ebef0dd9bf9b812bf75bda96743f2a6c5734a02092ae7f721c048d156d5fabae"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae1d6df168efb88d7d522664693607b80b4080be6750c913eefb77e34c12c71a"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f9899c94762343f2cc2fc64c13e7cae4c3cc65cdfc87dd810a31654c9b7358cc"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:99457f184ad90235cfe8461c4d70ab7dd2680e28821c29eca00252ba90308c78"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18f469a3d2a2fdafe99296a87e8a4c37748b5080a26b806a707f25a902c040a8"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7cdf28938ac6b8b49ae5e92f2735056a7ba99c9b110a474473fd71185c1af5d"}, + {file = "pydantic_core-2.18.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:938cb21650855054dc54dfd9120a851c974f95450f00683399006aa6e8abb057"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:44cd83ab6a51da80fb5adbd9560e26018e2ac7826f9626bc06ca3dc074cd198b"}, + {file = "pydantic_core-2.18.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:972658f4a72d02b8abfa2581d92d59f59897d2e9f7e708fdabe922f9087773af"}, + {file = "pydantic_core-2.18.4-cp38-none-win32.whl", hash = "sha256:1d886dc848e60cb7666f771e406acae54ab279b9f1e4143babc9c2258213daa2"}, + {file = "pydantic_core-2.18.4-cp38-none-win_amd64.whl", hash = "sha256:bb4462bd43c2460774914b8525f79b00f8f407c945d50881568f294c1d9b4443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:44a688331d4a4e2129140a8118479443bd6f1905231138971372fcde37e43528"}, + {file = "pydantic_core-2.18.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a2fdd81edd64342c85ac7cf2753ccae0b79bf2dfa063785503cb85a7d3593223"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:86110d7e1907ab36691f80b33eb2da87d780f4739ae773e5fc83fb272f88825f"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46387e38bd641b3ee5ce247563b60c5ca098da9c56c75c157a05eaa0933ed154"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:123c3cec203e3f5ac7b000bd82235f1a3eced8665b63d18be751f115588fea30"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:dc1803ac5c32ec324c5261c7209e8f8ce88e83254c4e1aebdc8b0a39f9ddb443"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53db086f9f6ab2b4061958d9c276d1dbe3690e8dd727d6abf2321d6cce37fa94"}, + {file = "pydantic_core-2.18.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:abc267fa9837245cc28ea6929f19fa335f3dc330a35d2e45509b6566dc18be23"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:a0d829524aaefdebccb869eed855e2d04c21d2d7479b6cada7ace5448416597b"}, + {file = "pydantic_core-2.18.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:509daade3b8649f80d4e5ff21aa5673e4ebe58590b25fe42fac5f0f52c6f034a"}, + {file = "pydantic_core-2.18.4-cp39-none-win32.whl", hash = "sha256:ca26a1e73c48cfc54c4a76ff78df3727b9d9f4ccc8dbee4ae3f73306a591676d"}, + {file = "pydantic_core-2.18.4-cp39-none-win_amd64.whl", hash = "sha256:c67598100338d5d985db1b3d21f3619ef392e185e71b8d52bceacc4a7771ea7e"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:574d92eac874f7f4db0ca653514d823a0d22e2354359d0759e3f6a406db5d55d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1f4d26ceb5eb9eed4af91bebeae4b06c3fb28966ca3a8fb765208cf6b51102ab"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:77450e6d20016ec41f43ca4a6c63e9fdde03f0ae3fe90e7c27bdbeaece8b1ed4"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d323a01da91851a4f17bf592faf46149c9169d68430b3146dcba2bb5e5719abc"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:43d447dd2ae072a0065389092a231283f62d960030ecd27565672bd40746c507"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:578e24f761f3b425834f297b9935e1ce2e30f51400964ce4801002435a1b41ef"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:81b5efb2f126454586d0f40c4d834010979cb80785173d1586df845a632e4e6d"}, + {file = "pydantic_core-2.18.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ab86ce7c8f9bea87b9d12c7f0af71102acbf5ecbc66c17796cff45dae54ef9a5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:90afc12421df2b1b4dcc975f814e21bc1754640d502a2fbcc6d41e77af5ec312"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:51991a89639a912c17bef4b45c87bd83593aee0437d8102556af4885811d59f5"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:293afe532740370aba8c060882f7d26cfd00c94cae32fd2e212a3a6e3b7bc15e"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b48ece5bde2e768197a2d0f6e925f9d7e3e826f0ad2271120f8144a9db18d5c8"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:eae237477a873ab46e8dd748e515c72c0c804fb380fbe6c85533c7de51f23a8f"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:834b5230b5dfc0c1ec37b2fda433b271cbbc0e507560b5d1588e2cc1148cf1ce"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:e858ac0a25074ba4bce653f9b5d0a85b7456eaddadc0ce82d3878c22489fa4ee"}, + {file = "pydantic_core-2.18.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2fd41f6eff4c20778d717af1cc50eca52f5afe7805ee530a4fbd0bae284f16e9"}, + {file = "pydantic_core-2.18.4.tar.gz", hash = "sha256:ec3beeada09ff865c344ff3bc2f427f5e6c26401cc6113d77e372c3fdac73864"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.18.0" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pymdown-extensions" +version = "10.8.1" +description = "Extension pack for Python Markdown." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pymdown_extensions-10.8.1-py3-none-any.whl", hash = "sha256:f938326115884f48c6059c67377c46cf631c733ef3629b6eed1349989d1b30cb"}, + {file = "pymdown_extensions-10.8.1.tar.gz", hash = "sha256:3ab1db5c9e21728dabf75192d71471f8e50f216627e9a1fa9535ecb0231b9940"}, +] + +[package.dependencies] +markdown = ">=3.6" +pyyaml = "*" + +[package.extras] +extra = ["pygments (>=2.12)"] + +[[package]] +name = "python-dateutil" +version = "2.9.0.post0" +description = "Extensions to the standard Python datetime module" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +files = [ + {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, + {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, +] + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pywin32" +version = "306" +description = "Python for Window Extensions" +optional = false +python-versions = "*" +files = [ + {file = "pywin32-306-cp310-cp310-win32.whl", hash = "sha256:06d3420a5155ba65f0b72f2699b5bacf3109f36acbe8923765c22938a69dfc8d"}, + {file = "pywin32-306-cp310-cp310-win_amd64.whl", hash = "sha256:84f4471dbca1887ea3803d8848a1616429ac94a4a8d05f4bc9c5dcfd42ca99c8"}, + {file = "pywin32-306-cp311-cp311-win32.whl", hash = "sha256:e65028133d15b64d2ed8f06dd9fbc268352478d4f9289e69c190ecd6818b6407"}, + {file = "pywin32-306-cp311-cp311-win_amd64.whl", hash = "sha256:a7639f51c184c0272e93f244eb24dafca9b1855707d94c192d4a0b4c01e1100e"}, + {file = "pywin32-306-cp311-cp311-win_arm64.whl", hash = "sha256:70dba0c913d19f942a2db25217d9a1b726c278f483a919f1abfed79c9cf64d3a"}, + {file = "pywin32-306-cp312-cp312-win32.whl", hash = "sha256:383229d515657f4e3ed1343da8be101000562bf514591ff383ae940cad65458b"}, + {file = "pywin32-306-cp312-cp312-win_amd64.whl", hash = "sha256:37257794c1ad39ee9be652da0462dc2e394c8159dfd913a8a4e8eb6fd346da0e"}, + {file = "pywin32-306-cp312-cp312-win_arm64.whl", hash = "sha256:5821ec52f6d321aa59e2db7e0a35b997de60c201943557d108af9d4ae1ec7040"}, + {file = "pywin32-306-cp37-cp37m-win32.whl", hash = "sha256:1c73ea9a0d2283d889001998059f5eaaba3b6238f767c9cf2833b13e6a685f65"}, + {file = "pywin32-306-cp37-cp37m-win_amd64.whl", hash = "sha256:72c5f621542d7bdd4fdb716227be0dd3f8565c11b280be6315b06ace35487d36"}, + {file = "pywin32-306-cp38-cp38-win32.whl", hash = "sha256:e4c092e2589b5cf0d365849e73e02c391c1349958c5ac3e9d5ccb9a28e017b3a"}, + {file = "pywin32-306-cp38-cp38-win_amd64.whl", hash = "sha256:e8ac1ae3601bee6ca9f7cb4b5363bf1c0badb935ef243c4733ff9a393b1690c0"}, + {file = "pywin32-306-cp39-cp39-win32.whl", hash = "sha256:e25fd5b485b55ac9c057f67d94bc203f3f6595078d1fb3b458c9c28b7153a802"}, + {file = "pywin32-306-cp39-cp39-win_amd64.whl", hash = "sha256:39b61c15272833b5c329a2989999dcae836b1eed650252ab1b7bfbe1d59f30f4"}, +] + +[[package]] +name = "pyyaml" +version = "6.0.1" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.6" +files = [ + {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, + {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, + {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, + {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, + {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, + {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, + {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, + {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, + {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, + {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, + {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, + {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, + {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, + {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, + {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, + {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, + {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, + {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, + {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, + {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, + {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, + {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, + {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, + {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, + {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, + {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, + {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, + {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, + {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, + {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, + {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, + {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, +] + +[[package]] +name = "pyyaml-env-tag" +version = "0.1" +description = "A custom YAML tag for referencing environment variables in YAML files. " +optional = false +python-versions = ">=3.6" +files = [ + {file = "pyyaml_env_tag-0.1-py3-none-any.whl", hash = "sha256:af31106dec8a4d68c60207c1886031cbf839b68aa7abccdb19868200532c2069"}, + {file = "pyyaml_env_tag-0.1.tar.gz", hash = "sha256:70092675bda14fdec33b31ba77e7543de9ddc88f2e5b99160396572d11525bdb"}, +] + +[package.dependencies] +pyyaml = "*" + +[[package]] +name = "pyzmq" +version = "26.0.3" +description = "Python bindings for 0MQ" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_15_universal2.whl", hash = "sha256:44dd6fc3034f1eaa72ece33588867df9e006a7303725a12d64c3dff92330f625"}, + {file = "pyzmq-26.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:acb704195a71ac5ea5ecf2811c9ee19ecdc62b91878528302dd0be1b9451cc90"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5dbb9c997932473a27afa93954bb77a9f9b786b4ccf718d903f35da3232317de"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6bcb34f869d431799c3ee7d516554797f7760cb2198ecaa89c3f176f72d062be"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:38ece17ec5f20d7d9b442e5174ae9f020365d01ba7c112205a4d59cf19dc38ee"}, + {file = "pyzmq-26.0.3-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:ba6e5e6588e49139a0979d03a7deb9c734bde647b9a8808f26acf9c547cab1bf"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:3bf8b000a4e2967e6dfdd8656cd0757d18c7e5ce3d16339e550bd462f4857e59"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:2136f64fbb86451dbbf70223635a468272dd20075f988a102bf8a3f194a411dc"}, + {file = "pyzmq-26.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e8918973fbd34e7814f59143c5f600ecd38b8038161239fd1a3d33d5817a38b8"}, + {file = "pyzmq-26.0.3-cp310-cp310-win32.whl", hash = "sha256:0aaf982e68a7ac284377d051c742610220fd06d330dcd4c4dbb4cdd77c22a537"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f1a9b7d00fdf60b4039f4455afd031fe85ee8305b019334b72dcf73c567edc47"}, + {file = "pyzmq-26.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:80b12f25d805a919d53efc0a5ad7c0c0326f13b4eae981a5d7b7cc343318ebb7"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_15_universal2.whl", hash = "sha256:a72a84570f84c374b4c287183debc776dc319d3e8ce6b6a0041ce2e400de3f32"}, + {file = "pyzmq-26.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7ca684ee649b55fd8f378127ac8462fb6c85f251c2fb027eb3c887e8ee347bcd"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e222562dc0f38571c8b1ffdae9d7adb866363134299264a1958d077800b193b7"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f17cde1db0754c35a91ac00b22b25c11da6eec5746431d6e5092f0cd31a3fea9"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4b7c0c0b3244bb2275abe255d4a30c050d541c6cb18b870975553f1fb6f37527"}, + {file = "pyzmq-26.0.3-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:ac97a21de3712afe6a6c071abfad40a6224fd14fa6ff0ff8d0c6e6cd4e2f807a"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:88b88282e55fa39dd556d7fc04160bcf39dea015f78e0cecec8ff4f06c1fc2b5"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:72b67f966b57dbd18dcc7efbc1c7fc9f5f983e572db1877081f075004614fcdd"}, + {file = "pyzmq-26.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f4b6cecbbf3b7380f3b61de3a7b93cb721125dc125c854c14ddc91225ba52f83"}, + {file = "pyzmq-26.0.3-cp311-cp311-win32.whl", hash = "sha256:eed56b6a39216d31ff8cd2f1d048b5bf1700e4b32a01b14379c3b6dde9ce3aa3"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:3191d312c73e3cfd0f0afdf51df8405aafeb0bad71e7ed8f68b24b63c4f36500"}, + {file = "pyzmq-26.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:b6907da3017ef55139cf0e417c5123a84c7332520e73a6902ff1f79046cd3b94"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_15_universal2.whl", hash = "sha256:068ca17214038ae986d68f4a7021f97e187ed278ab6dccb79f837d765a54d753"}, + {file = "pyzmq-26.0.3-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7821d44fe07335bea256b9f1f41474a642ca55fa671dfd9f00af8d68a920c2d4"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eeb438a26d87c123bb318e5f2b3d86a36060b01f22fbdffd8cf247d52f7c9a2b"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:69ea9d6d9baa25a4dc9cef5e2b77b8537827b122214f210dd925132e34ae9b12"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7daa3e1369355766dea11f1d8ef829905c3b9da886ea3152788dc25ee6079e02"}, + {file = "pyzmq-26.0.3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:6ca7a9a06b52d0e38ccf6bca1aeff7be178917893f3883f37b75589d42c4ac20"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1b7d0e124948daa4d9686d421ef5087c0516bc6179fdcf8828b8444f8e461a77"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:e746524418b70f38550f2190eeee834db8850088c834d4c8406fbb9bc1ae10b2"}, + {file = "pyzmq-26.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:6b3146f9ae6af82c47a5282ac8803523d381b3b21caeae0327ed2f7ecb718798"}, + {file = "pyzmq-26.0.3-cp312-cp312-win32.whl", hash = "sha256:2b291d1230845871c00c8462c50565a9cd6026fe1228e77ca934470bb7d70ea0"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:926838a535c2c1ea21c903f909a9a54e675c2126728c21381a94ddf37c3cbddf"}, + {file = "pyzmq-26.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:5bf6c237f8c681dfb91b17f8435b2735951f0d1fad10cc5dfd96db110243370b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:0c0991f5a96a8e620f7691e61178cd8f457b49e17b7d9cfa2067e2a0a89fc1d5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dbf012d8fcb9f2cf0643b65df3b355fdd74fc0035d70bb5c845e9e30a3a4654b"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:01fbfbeb8249a68d257f601deb50c70c929dc2dfe683b754659569e502fbd3aa"}, + {file = "pyzmq-26.0.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c8eb19abe87029c18f226d42b8a2c9efdd139d08f8bf6e085dd9075446db450"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:5344b896e79800af86ad643408ca9aa303a017f6ebff8cee5a3163c1e9aec987"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:204e0f176fd1d067671157d049466869b3ae1fc51e354708b0dc41cf94e23a3a"}, + {file = "pyzmq-26.0.3-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a42db008d58530efa3b881eeee4991146de0b790e095f7ae43ba5cc612decbc5"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win32.whl", hash = "sha256:8d7a498671ca87e32b54cb47c82a92b40130a26c5197d392720a1bce1b3c77cf"}, + {file = "pyzmq-26.0.3-cp37-cp37m-win_amd64.whl", hash = "sha256:3b4032a96410bdc760061b14ed6a33613ffb7f702181ba999df5d16fb96ba16a"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_15_universal2.whl", hash = "sha256:2cc4e280098c1b192c42a849de8de2c8e0f3a84086a76ec5b07bfee29bda7d18"}, + {file = "pyzmq-26.0.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:5bde86a2ed3ce587fa2b207424ce15b9a83a9fa14422dcc1c5356a13aed3df9d"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:34106f68e20e6ff253c9f596ea50397dbd8699828d55e8fa18bd4323d8d966e6"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ebbbd0e728af5db9b04e56389e2299a57ea8b9dd15c9759153ee2455b32be6ad"}, + {file = "pyzmq-26.0.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f6b1d1c631e5940cac5a0b22c5379c86e8df6a4ec277c7a856b714021ab6cfad"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:e891ce81edd463b3b4c3b885c5603c00141151dd9c6936d98a680c8c72fe5c67"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:9b273ecfbc590a1b98f014ae41e5cf723932f3b53ba9367cfb676f838038b32c"}, + {file = "pyzmq-26.0.3-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b32bff85fb02a75ea0b68f21e2412255b5731f3f389ed9aecc13a6752f58ac97"}, + {file = "pyzmq-26.0.3-cp38-cp38-win32.whl", hash = "sha256:f6c21c00478a7bea93caaaef9e7629145d4153b15a8653e8bb4609d4bc70dbfc"}, + {file = "pyzmq-26.0.3-cp38-cp38-win_amd64.whl", hash = "sha256:3401613148d93ef0fd9aabdbddb212de3db7a4475367f49f590c837355343972"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_15_universal2.whl", hash = "sha256:2ed8357f4c6e0daa4f3baf31832df8a33334e0fe5b020a61bc8b345a3db7a606"}, + {file = "pyzmq-26.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c1c8f2a2ca45292084c75bb6d3a25545cff0ed931ed228d3a1810ae3758f975f"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b63731993cdddcc8e087c64e9cf003f909262b359110070183d7f3025d1c56b5"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b3cd31f859b662ac5d7f4226ec7d8bd60384fa037fc02aee6ff0b53ba29a3ba8"}, + {file = "pyzmq-26.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:115f8359402fa527cf47708d6f8a0f8234f0e9ca0cab7c18c9c189c194dbf620"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:715bdf952b9533ba13dfcf1f431a8f49e63cecc31d91d007bc1deb914f47d0e4"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:e1258c639e00bf5e8a522fec6c3eaa3e30cf1c23a2f21a586be7e04d50c9acab"}, + {file = "pyzmq-26.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:15c59e780be8f30a60816a9adab900c12a58d79c1ac742b4a8df044ab2a6d920"}, + {file = "pyzmq-26.0.3-cp39-cp39-win32.whl", hash = "sha256:d0cdde3c78d8ab5b46595054e5def32a755fc028685add5ddc7403e9f6de9879"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ce828058d482ef860746bf532822842e0ff484e27f540ef5c813d516dd8896d2"}, + {file = "pyzmq-26.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:788f15721c64109cf720791714dc14afd0f449d63f3a5487724f024345067381"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:2c18645ef6294d99b256806e34653e86236eb266278c8ec8112622b61db255de"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7e6bc96ebe49604df3ec2c6389cc3876cabe475e6bfc84ced1bf4e630662cb35"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:971e8990c5cc4ddcff26e149398fc7b0f6a042306e82500f5e8db3b10ce69f84"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8416c23161abd94cc7da80c734ad7c9f5dbebdadfdaa77dad78244457448223"}, + {file = "pyzmq-26.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:082a2988364b60bb5de809373098361cf1dbb239623e39e46cb18bc035ed9c0c"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d57dfbf9737763b3a60d26e6800e02e04284926329aee8fb01049635e957fe81"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:77a85dca4c2430ac04dc2a2185c2deb3858a34fe7f403d0a946fa56970cf60a1"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:4c82a6d952a1d555bf4be42b6532927d2a5686dd3c3e280e5f63225ab47ac1f5"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4496b1282c70c442809fc1b151977c3d967bfb33e4e17cedbf226d97de18f709"}, + {file = "pyzmq-26.0.3-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:e4946d6bdb7ba972dfda282f9127e5756d4f299028b1566d1245fa0d438847e6"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:03c0ae165e700364b266876d712acb1ac02693acd920afa67da2ebb91a0b3c09"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:3e3070e680f79887d60feeda051a58d0ac36622e1759f305a41059eff62c6da7"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6ca08b840fe95d1c2bd9ab92dac5685f949fc6f9ae820ec16193e5ddf603c3b2"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e76654e9dbfb835b3518f9938e565c7806976c07b37c33526b574cc1a1050480"}, + {file = "pyzmq-26.0.3-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:871587bdadd1075b112e697173e946a07d722459d20716ceb3d1bd6c64bd08ce"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d0a2d1bd63a4ad79483049b26514e70fa618ce6115220da9efdff63688808b17"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0270b49b6847f0d106d64b5086e9ad5dc8a902413b5dbbb15d12b60f9c1747a4"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:703c60b9910488d3d0954ca585c34f541e506a091a41930e663a098d3b794c67"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:74423631b6be371edfbf7eabb02ab995c2563fee60a80a30829176842e71722a"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4adfbb5451196842a88fda3612e2c0414134874bffb1c2ce83ab4242ec9e027d"}, + {file = "pyzmq-26.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:3516119f4f9b8671083a70b6afaa0a070f5683e431ab3dc26e9215620d7ca1ad"}, + {file = "pyzmq-26.0.3.tar.gz", hash = "sha256:dba7d9f2e047dfa2bca3b01f4f84aa5246725203d6284e3790f2ca15fba6b40a"}, +] + +[package.dependencies] +cffi = {version = "*", markers = "implementation_name == \"pypy\""} + +[[package]] +name = "referencing" +version = "0.35.1" +description = "JSON Referencing + Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "referencing-0.35.1-py3-none-any.whl", hash = "sha256:eda6d3234d62814d1c64e305c1331c9a3a6132da475ab6382eaa997b21ee75de"}, + {file = "referencing-0.35.1.tar.gz", hash = "sha256:25b42124a6c8b632a425174f24087783efb348a6f1e0008e63cd4466fedf703c"}, +] + +[package.dependencies] +attrs = ">=22.2.0" +rpds-py = ">=0.7.0" + +[[package]] +name = "regex" +version = "2024.5.15" +description = "Alternative regular expression module, to replace re." +optional = false +python-versions = ">=3.8" +files = [ + {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a81e3cfbae20378d75185171587cbf756015ccb14840702944f014e0d93ea09f"}, + {file = "regex-2024.5.15-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7b59138b219ffa8979013be7bc85bb60c6f7b7575df3d56dc1e403a438c7a3f6"}, + {file = "regex-2024.5.15-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0bd000c6e266927cb7a1bc39d55be95c4b4f65c5be53e659537537e019232b1"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5eaa7ddaf517aa095fa8da0b5015c44d03da83f5bd49c87961e3c997daed0de7"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ba68168daedb2c0bab7fd7e00ced5ba90aebf91024dea3c88ad5063c2a562cca"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6e8d717bca3a6e2064fc3a08df5cbe366369f4b052dcd21b7416e6d71620dca1"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1337b7dbef9b2f71121cdbf1e97e40de33ff114801263b275aafd75303bd62b5"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f9ebd0a36102fcad2f03696e8af4ae682793a5d30b46c647eaf280d6cfb32796"}, + {file = "regex-2024.5.15-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9efa1a32ad3a3ea112224897cdaeb6aa00381627f567179c0314f7b65d354c62"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:1595f2d10dff3d805e054ebdc41c124753631b6a471b976963c7b28543cf13b0"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b802512f3e1f480f41ab5f2cfc0e2f761f08a1f41092d6718868082fc0d27143"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a0981022dccabca811e8171f913de05720590c915b033b7e601f35ce4ea7019f"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:19068a6a79cf99a19ccefa44610491e9ca02c2be3305c7760d3831d38a467a6f"}, + {file = "regex-2024.5.15-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1b5269484f6126eee5e687785e83c6b60aad7663dafe842b34691157e5083e53"}, + {file = "regex-2024.5.15-cp310-cp310-win32.whl", hash = "sha256:ada150c5adfa8fbcbf321c30c751dc67d2f12f15bd183ffe4ec7cde351d945b3"}, + {file = "regex-2024.5.15-cp310-cp310-win_amd64.whl", hash = "sha256:ac394ff680fc46b97487941f5e6ae49a9f30ea41c6c6804832063f14b2a5a145"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f5b1dff3ad008dccf18e652283f5e5339d70bf8ba7c98bf848ac33db10f7bc7a"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c6a2b494a76983df8e3d3feea9b9ffdd558b247e60b92f877f93a1ff43d26656"}, + {file = "regex-2024.5.15-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a32b96f15c8ab2e7d27655969a23895eb799de3665fa94349f3b2fbfd547236f"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:10002e86e6068d9e1c91eae8295ef690f02f913c57db120b58fdd35a6bb1af35"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ec54d5afa89c19c6dd8541a133be51ee1017a38b412b1321ccb8d6ddbeb4cf7d"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:10e4ce0dca9ae7a66e6089bb29355d4432caed736acae36fef0fdd7879f0b0cb"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e507ff1e74373c4d3038195fdd2af30d297b4f0950eeda6f515ae3d84a1770f"}, + {file = "regex-2024.5.15-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d1f059a4d795e646e1c37665b9d06062c62d0e8cc3c511fe01315973a6542e40"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0721931ad5fe0dda45d07f9820b90b2148ccdd8e45bb9e9b42a146cb4f695649"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:833616ddc75ad595dee848ad984d067f2f31be645d603e4d158bba656bbf516c"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:287eb7f54fc81546346207c533ad3c2c51a8d61075127d7f6d79aaf96cdee890"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:19dfb1c504781a136a80ecd1fff9f16dddf5bb43cec6871778c8a907a085bb3d"}, + {file = "regex-2024.5.15-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:119af6e56dce35e8dfb5222573b50c89e5508d94d55713c75126b753f834de68"}, + {file = "regex-2024.5.15-cp311-cp311-win32.whl", hash = "sha256:1c1c174d6ec38d6c8a7504087358ce9213d4332f6293a94fbf5249992ba54efa"}, + {file = "regex-2024.5.15-cp311-cp311-win_amd64.whl", hash = "sha256:9e717956dcfd656f5055cc70996ee2cc82ac5149517fc8e1b60261b907740201"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:632b01153e5248c134007209b5c6348a544ce96c46005d8456de1d552455b014"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:e64198f6b856d48192bf921421fdd8ad8eb35e179086e99e99f711957ffedd6e"}, + {file = "regex-2024.5.15-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:68811ab14087b2f6e0fc0c2bae9ad689ea3584cad6917fc57be6a48bbd012c49"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8ec0c2fea1e886a19c3bee0cd19d862b3aa75dcdfb42ebe8ed30708df64687a"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d0c0c0003c10f54a591d220997dd27d953cd9ccc1a7294b40a4be5312be8797b"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2431b9e263af1953c55abbd3e2efca67ca80a3de8a0437cb58e2421f8184717a"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4a605586358893b483976cffc1723fb0f83e526e8f14c6e6614e75919d9862cf"}, + {file = "regex-2024.5.15-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:391d7f7f1e409d192dba8bcd42d3e4cf9e598f3979cdaed6ab11288da88cb9f2"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9ff11639a8d98969c863d4617595eb5425fd12f7c5ef6621a4b74b71ed8726d5"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4eee78a04e6c67e8391edd4dad3279828dd66ac4b79570ec998e2155d2e59fd5"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:8fe45aa3f4aa57faabbc9cb46a93363edd6197cbc43523daea044e9ff2fea83e"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:d0a3d8d6acf0c78a1fff0e210d224b821081330b8524e3e2bc5a68ef6ab5803d"}, + {file = "regex-2024.5.15-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c486b4106066d502495b3025a0a7251bf37ea9540433940a23419461ab9f2a80"}, + {file = "regex-2024.5.15-cp312-cp312-win32.whl", hash = "sha256:c49e15eac7c149f3670b3e27f1f28a2c1ddeccd3a2812cba953e01be2ab9b5fe"}, + {file = "regex-2024.5.15-cp312-cp312-win_amd64.whl", hash = "sha256:673b5a6da4557b975c6c90198588181029c60793835ce02f497ea817ff647cb2"}, + {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:87e2a9c29e672fc65523fb47a90d429b70ef72b901b4e4b1bd42387caf0d6835"}, + {file = "regex-2024.5.15-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:c3bea0ba8b73b71b37ac833a7f3fd53825924165da6a924aec78c13032f20850"}, + {file = "regex-2024.5.15-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:bfc4f82cabe54f1e7f206fd3d30fda143f84a63fe7d64a81558d6e5f2e5aaba9"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e5bb9425fe881d578aeca0b2b4b3d314ec88738706f66f219c194d67179337cb"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:64c65783e96e563103d641760664125e91bd85d8e49566ee560ded4da0d3e704"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cf2430df4148b08fb4324b848672514b1385ae3807651f3567871f130a728cc3"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5397de3219a8b08ae9540c48f602996aa6b0b65d5a61683e233af8605c42b0f2"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:455705d34b4154a80ead722f4f185b04c4237e8e8e33f265cd0798d0e44825fa"}, + {file = "regex-2024.5.15-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:b2b6f1b3bb6f640c1a92be3bbfbcb18657b125b99ecf141fb3310b5282c7d4ed"}, + {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:3ad070b823ca5890cab606c940522d05d3d22395d432f4aaaf9d5b1653e47ced"}, + {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5b5467acbfc153847d5adb21e21e29847bcb5870e65c94c9206d20eb4e99a384"}, + {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:e6662686aeb633ad65be2a42b4cb00178b3fbf7b91878f9446075c404ada552f"}, + {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:2b4c884767504c0e2401babe8b5b7aea9148680d2e157fa28f01529d1f7fcf67"}, + {file = "regex-2024.5.15-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3cd7874d57f13bf70078f1ff02b8b0aa48d5b9ed25fc48547516c6aba36f5741"}, + {file = "regex-2024.5.15-cp38-cp38-win32.whl", hash = "sha256:e4682f5ba31f475d58884045c1a97a860a007d44938c4c0895f41d64481edbc9"}, + {file = "regex-2024.5.15-cp38-cp38-win_amd64.whl", hash = "sha256:d99ceffa25ac45d150e30bd9ed14ec6039f2aad0ffa6bb87a5936f5782fc1569"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13cdaf31bed30a1e1c2453ef6015aa0983e1366fad2667657dbcac7b02f67133"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:cac27dcaa821ca271855a32188aa61d12decb6fe45ffe3e722401fe61e323cd1"}, + {file = "regex-2024.5.15-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:7dbe2467273b875ea2de38ded4eba86cbcbc9a1a6d0aa11dcf7bd2e67859c435"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:64f18a9a3513a99c4bef0e3efd4c4a5b11228b48aa80743be822b71e132ae4f5"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d347a741ea871c2e278fde6c48f85136c96b8659b632fb57a7d1ce1872547600"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1878b8301ed011704aea4c806a3cadbd76f84dece1ec09cc9e4dc934cfa5d4da"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4babf07ad476aaf7830d77000874d7611704a7fcf68c9c2ad151f5d94ae4bfc4"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35cb514e137cb3488bce23352af3e12fb0dbedd1ee6e60da053c69fb1b29cc6c"}, + {file = "regex-2024.5.15-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:cdd09d47c0b2efee9378679f8510ee6955d329424c659ab3c5e3a6edea696294"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:72d7a99cd6b8f958e85fc6ca5b37c4303294954eac1376535b03c2a43eb72629"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:a094801d379ab20c2135529948cb84d417a2169b9bdceda2a36f5f10977ebc16"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:c0c18345010870e58238790a6779a1219b4d97bd2e77e1140e8ee5d14df071aa"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:16093f563098448ff6b1fa68170e4acbef94e6b6a4e25e10eae8598bb1694b5d"}, + {file = "regex-2024.5.15-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e38a7d4e8f633a33b4c7350fbd8bad3b70bf81439ac67ac38916c4a86b465456"}, + {file = "regex-2024.5.15-cp39-cp39-win32.whl", hash = "sha256:71a455a3c584a88f654b64feccc1e25876066c4f5ef26cd6dd711308aa538694"}, + {file = "regex-2024.5.15-cp39-cp39-win_amd64.whl", hash = "sha256:cab12877a9bdafde5500206d1020a584355a97884dfd388af3699e9137bf7388"}, + {file = "regex-2024.5.15.tar.gz", hash = "sha256:d3ee02d9e5f482cc8309134a91eeaacbdd2261ba111b0fef3748eeb4913e6a2c"}, +] + +[[package]] +name = "requests" +version = "2.32.3" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.8" +files = [ + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "rpds-py" +version = "0.18.1" +description = "Python bindings to Rust's persistent data structures (rpds)" +optional = false +python-versions = ">=3.8" +files = [ + {file = "rpds_py-0.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:d31dea506d718693b6b2cffc0648a8929bdc51c70a311b2770f09611caa10d53"}, + {file = "rpds_py-0.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:732672fbc449bab754e0b15356c077cc31566df874964d4801ab14f71951ea80"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a98a1f0552b5f227a3d6422dbd61bc6f30db170939bd87ed14f3c339aa6c7c9"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:7f1944ce16401aad1e3f7d312247b3d5de7981f634dc9dfe90da72b87d37887d"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38e14fb4e370885c4ecd734f093a2225ee52dc384b86fa55fe3f74638b2cfb09"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:08d74b184f9ab6289b87b19fe6a6d1a97fbfea84b8a3e745e87a5de3029bf944"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d70129cef4a8d979caa37e7fe957202e7eee8ea02c5e16455bc9808a59c6b2f0"}, + {file = "rpds_py-0.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ce0bb20e3a11bd04461324a6a798af34d503f8d6f1aa3d2aa8901ceaf039176d"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:81c5196a790032e0fc2464c0b4ab95f8610f96f1f2fa3d4deacce6a79852da60"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f3027be483868c99b4985fda802a57a67fdf30c5d9a50338d9db646d590198da"}, + {file = "rpds_py-0.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d44607f98caa2961bab4fa3c4309724b185b464cdc3ba6f3d7340bac3ec97cc1"}, + {file = "rpds_py-0.18.1-cp310-none-win32.whl", hash = "sha256:c273e795e7a0f1fddd46e1e3cb8be15634c29ae8ff31c196debb620e1edb9333"}, + {file = "rpds_py-0.18.1-cp310-none-win_amd64.whl", hash = "sha256:8352f48d511de5f973e4f2f9412736d7dea76c69faa6d36bcf885b50c758ab9a"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:6b5ff7e1d63a8281654b5e2896d7f08799378e594f09cf3674e832ecaf396ce8"}, + {file = "rpds_py-0.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8927638a4d4137a289e41d0fd631551e89fa346d6dbcfc31ad627557d03ceb6d"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:154bf5c93d79558b44e5b50cc354aa0459e518e83677791e6adb0b039b7aa6a7"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07f2139741e5deb2c5154a7b9629bc5aa48c766b643c1a6750d16f865a82c5fc"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8c7672e9fba7425f79019db9945b16e308ed8bc89348c23d955c8c0540da0a07"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:489bdfe1abd0406eba6b3bb4fdc87c7fa40f1031de073d0cfb744634cc8fa261"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c20f05e8e3d4fc76875fc9cb8cf24b90a63f5a1b4c5b9273f0e8225e169b100"}, + {file = "rpds_py-0.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:967342e045564cef76dfcf1edb700b1e20838d83b1aa02ab313e6a497cf923b8"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:2cc7c1a47f3a63282ab0f422d90ddac4aa3034e39fc66a559ab93041e6505da7"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f7afbfee1157e0f9376c00bb232e80a60e59ed716e3211a80cb8506550671e6e"}, + {file = "rpds_py-0.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9e6934d70dc50f9f8ea47081ceafdec09245fd9f6032669c3b45705dea096b88"}, + {file = "rpds_py-0.18.1-cp311-none-win32.whl", hash = "sha256:c69882964516dc143083d3795cb508e806b09fc3800fd0d4cddc1df6c36e76bb"}, + {file = "rpds_py-0.18.1-cp311-none-win_amd64.whl", hash = "sha256:70a838f7754483bcdc830444952fd89645569e7452e3226de4a613a4c1793fb2"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:3dd3cd86e1db5aadd334e011eba4e29d37a104b403e8ca24dcd6703c68ca55b3"}, + {file = "rpds_py-0.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:05f3d615099bd9b13ecf2fc9cf2d839ad3f20239c678f461c753e93755d629ee"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35b2b771b13eee8729a5049c976197ff58a27a3829c018a04341bcf1ae409b2b"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ee17cd26b97d537af8f33635ef38be873073d516fd425e80559f4585a7b90c43"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b646bf655b135ccf4522ed43d6902af37d3f5dbcf0da66c769a2b3938b9d8184"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:19ba472b9606c36716062c023afa2484d1e4220548751bda14f725a7de17b4f6"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e30ac5e329098903262dc5bdd7e2086e0256aa762cc8b744f9e7bf2a427d3f8"}, + {file = "rpds_py-0.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d58ad6317d188c43750cb76e9deacf6051d0f884d87dc6518e0280438648a9ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:e1735502458621921cee039c47318cb90b51d532c2766593be6207eec53e5c4c"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:f5bab211605d91db0e2995a17b5c6ee5edec1270e46223e513eaa20da20076ac"}, + {file = "rpds_py-0.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2fc24a329a717f9e2448f8cd1f960f9dac4e45b6224d60734edeb67499bab03a"}, + {file = "rpds_py-0.18.1-cp312-none-win32.whl", hash = "sha256:1805d5901779662d599d0e2e4159d8a82c0b05faa86ef9222bf974572286b2b6"}, + {file = "rpds_py-0.18.1-cp312-none-win_amd64.whl", hash = "sha256:720edcb916df872d80f80a1cc5ea9058300b97721efda8651efcd938a9c70a72"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:c827576e2fa017a081346dce87d532a5310241648eb3700af9a571a6e9fc7e74"}, + {file = "rpds_py-0.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:aa3679e751408d75a0b4d8d26d6647b6d9326f5e35c00a7ccd82b78ef64f65f8"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0abeee75434e2ee2d142d650d1e54ac1f8b01e6e6abdde8ffd6eeac6e9c38e20"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ed402d6153c5d519a0faf1bb69898e97fb31613b49da27a84a13935ea9164dfc"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:338dee44b0cef8b70fd2ef54b4e09bb1b97fc6c3a58fea5db6cc083fd9fc2724"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7750569d9526199c5b97e5a9f8d96a13300950d910cf04a861d96f4273d5b104"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:607345bd5912aacc0c5a63d45a1f73fef29e697884f7e861094e443187c02be5"}, + {file = "rpds_py-0.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:207c82978115baa1fd8d706d720b4a4d2b0913df1c78c85ba73fe6c5804505f0"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:6d1e42d2735d437e7e80bab4d78eb2e459af48c0a46e686ea35f690b93db792d"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:5463c47c08630007dc0fe99fb480ea4f34a89712410592380425a9b4e1611d8e"}, + {file = "rpds_py-0.18.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:06d218939e1bf2ca50e6b0ec700ffe755e5216a8230ab3e87c059ebb4ea06afc"}, + {file = "rpds_py-0.18.1-cp38-none-win32.whl", hash = "sha256:312fe69b4fe1ffbe76520a7676b1e5ac06ddf7826d764cc10265c3b53f96dbe9"}, + {file = "rpds_py-0.18.1-cp38-none-win_amd64.whl", hash = "sha256:9437ca26784120a279f3137ee080b0e717012c42921eb07861b412340f85bae2"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:19e515b78c3fc1039dd7da0a33c28c3154458f947f4dc198d3c72db2b6b5dc93"}, + {file = "rpds_py-0.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a7b28c5b066bca9a4eb4e2f2663012debe680f097979d880657f00e1c30875a0"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:673fdbbf668dd958eff750e500495ef3f611e2ecc209464f661bc82e9838991e"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d960de62227635d2e61068f42a6cb6aae91a7fe00fca0e3aeed17667c8a34611"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:352a88dc7892f1da66b6027af06a2e7e5d53fe05924cc2cfc56495b586a10b72"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e0ee01ad8260184db21468a6e1c37afa0529acc12c3a697ee498d3c2c4dcaf3"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e4c39ad2f512b4041343ea3c7894339e4ca7839ac38ca83d68a832fc8b3748ab"}, + {file = "rpds_py-0.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aaa71ee43a703c321906813bb252f69524f02aa05bf4eec85f0c41d5d62d0f4c"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:6cd8098517c64a85e790657e7b1e509b9fe07487fd358e19431cb120f7d96338"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4adec039b8e2928983f885c53b7cc4cda8965b62b6596501a0308d2703f8af1b"}, + {file = "rpds_py-0.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:32b7daaa3e9389db3695964ce8e566e3413b0c43e3394c05e4b243a4cd7bef26"}, + {file = "rpds_py-0.18.1-cp39-none-win32.whl", hash = "sha256:2625f03b105328729f9450c8badda34d5243231eef6535f80064d57035738360"}, + {file = "rpds_py-0.18.1-cp39-none-win_amd64.whl", hash = "sha256:bf18932d0003c8c4d51a39f244231986ab23ee057d235a12b2684ea26a353590"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:cbfbea39ba64f5e53ae2915de36f130588bba71245b418060ec3330ebf85678e"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:a3d456ff2a6a4d2adcdf3c1c960a36f4fd2fec6e3b4902a42a384d17cf4e7a65"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7700936ef9d006b7ef605dc53aa364da2de5a3aa65516a1f3ce73bf82ecfc7ae"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:51584acc5916212e1bf45edd17f3a6b05fe0cbb40482d25e619f824dccb679de"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:942695a206a58d2575033ff1e42b12b2aece98d6003c6bc739fbf33d1773b12f"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b906b5f58892813e5ba5c6056d6a5ad08f358ba49f046d910ad992196ea61397"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6f8e3fecca256fefc91bb6765a693d96692459d7d4c644660a9fff32e517843"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7732770412bab81c5a9f6d20aeb60ae943a9b36dcd990d876a773526468e7163"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:bd1105b50ede37461c1d51b9698c4f4be6e13e69a908ab7751e3807985fc0346"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:618916f5535784960f3ecf8111581f4ad31d347c3de66d02e728de460a46303c"}, + {file = "rpds_py-0.18.1-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:17c6d2155e2423f7e79e3bb18151c686d40db42d8645e7977442170c360194d4"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:6c4c4c3f878df21faf5fac86eda32671c27889e13570645a9eea0a1abdd50922"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:fab6ce90574645a0d6c58890e9bcaac8d94dff54fb51c69e5522a7358b80ab64"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:531796fb842b53f2695e94dc338929e9f9dbf473b64710c28af5a160b2a8927d"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:740884bc62a5e2bbb31e584f5d23b32320fd75d79f916f15a788d527a5e83644"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:998125738de0158f088aef3cb264a34251908dd2e5d9966774fdab7402edfab7"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e2be6e9dd4111d5b31ba3b74d17da54a8319d8168890fbaea4b9e5c3de630ae5"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d0cee71bc618cd93716f3c1bf56653740d2d13ddbd47673efa8bf41435a60daa"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2c3caec4ec5cd1d18e5dd6ae5194d24ed12785212a90b37f5f7f06b8bedd7139"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:27bba383e8c5231cd559affe169ca0b96ec78d39909ffd817f28b166d7ddd4d8"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_i686.whl", hash = "sha256:a888e8bdb45916234b99da2d859566f1e8a1d2275a801bb8e4a9644e3c7e7909"}, + {file = "rpds_py-0.18.1-pp38-pypy38_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6031b25fb1b06327b43d841f33842b383beba399884f8228a6bb3df3088485ff"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48c2faaa8adfacefcbfdb5f2e2e7bdad081e5ace8d182e5f4ade971f128e6bb3"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:d85164315bd68c0806768dc6bb0429c6f95c354f87485ee3593c4f6b14def2bd"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6afd80f6c79893cfc0574956f78a0add8c76e3696f2d6a15bca2c66c415cf2d4"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa242ac1ff583e4ec7771141606aafc92b361cd90a05c30d93e343a0c2d82a89"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d21be4770ff4e08698e1e8e0bce06edb6ea0626e7c8f560bc08222880aca6a6f"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5c45a639e93a0c5d4b788b2613bd637468edd62f8f95ebc6fcc303d58ab3f0a8"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:910e71711d1055b2768181efa0a17537b2622afeb0424116619817007f8a2b10"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b9bb1f182a97880f6078283b3505a707057c42bf55d8fca604f70dedfdc0772a"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1d54f74f40b1f7aaa595a02ff42ef38ca654b1469bef7d52867da474243cc633"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_i686.whl", hash = "sha256:8d2e182c9ee01135e11e9676e9a62dfad791a7a467738f06726872374a83db49"}, + {file = "rpds_py-0.18.1-pp39-pypy39_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:636a15acc588f70fda1661234761f9ed9ad79ebed3f2125d44be0862708b666e"}, + {file = "rpds_py-0.18.1.tar.gz", hash = "sha256:dc48b479d540770c811fbd1eb9ba2bb66951863e448efec2e2c102625328e92f"}, +] + +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] + +[[package]] +name = "smmap" +version = "5.0.1" +description = "A pure Python implementation of a sliding window memory map manager" +optional = false +python-versions = ">=3.7" +files = [ + {file = "smmap-5.0.1-py3-none-any.whl", hash = "sha256:e6d8668fa5f93e706934a62d7b4db19c8d9eb8cf2adbb75ef1b675aa332b69da"}, + {file = "smmap-5.0.1.tar.gz", hash = "sha256:dceeb6c0028fdb6734471eb07c0cd2aae706ccaecab45965ee83f11c8d3b1f62"}, +] + +[[package]] +name = "soupsieve" +version = "2.5" +description = "A modern CSS selector implementation for Beautiful Soup." +optional = false +python-versions = ">=3.8" +files = [ + {file = "soupsieve-2.5-py3-none-any.whl", hash = "sha256:eaa337ff55a1579b6549dc679565eac1e3d000563bcb1c8ab0d0fefbc0c2cdc7"}, + {file = "soupsieve-2.5.tar.gz", hash = "sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690"}, +] + +[[package]] +name = "stack-data" +version = "0.6.3" +description = "Extract data from python stack frames and tracebacks for informative displays" +optional = false +python-versions = "*" +files = [ + {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, + {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, +] + +[package.dependencies] +asttokens = ">=2.1.0" +executing = ">=1.2.0" +pure-eval = "*" + +[package.extras] +tests = ["cython", "littleutils", "pygments", "pytest", "typeguard"] + +[[package]] +name = "tenacity" +version = "8.4.1" +description = "Retry code until it succeeds" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, + {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, +] + +[package.extras] +doc = ["reno", "sphinx"] +test = ["pytest", "tornado (>=4.5)", "typeguard"] + +[[package]] +name = "tinycss2" +version = "1.3.0" +description = "A tiny CSS parser" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tinycss2-1.3.0-py3-none-any.whl", hash = "sha256:54a8dbdffb334d536851be0226030e9505965bb2f30f21a4a82c55fb2a80fae7"}, + {file = "tinycss2-1.3.0.tar.gz", hash = "sha256:152f9acabd296a8375fbca5b84c961ff95971fcfc32e79550c8df8e29118c54d"}, +] + +[package.dependencies] +webencodings = ">=0.4" + +[package.extras] +doc = ["sphinx", "sphinx_rtd_theme"] +test = ["pytest", "ruff"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[[package]] +name = "tornado" +version = "6.4.1" +description = "Tornado is a Python web framework and asynchronous networking library, originally developed at FriendFeed." +optional = false +python-versions = ">=3.8" +files = [ + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:163b0aafc8e23d8cdc3c9dfb24c5368af84a81e3364745ccb4427669bf84aec8"}, + {file = "tornado-6.4.1-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:6d5ce3437e18a2b66fbadb183c1d3364fb03f2be71299e7d10dbeeb69f4b2a14"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e2e20b9113cd7293f164dc46fffb13535266e713cdb87bd2d15ddb336e96cfc4"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8ae50a504a740365267b2a8d1a90c9fbc86b780a39170feca9bcc1787ff80842"}, + {file = "tornado-6.4.1-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:613bf4ddf5c7a95509218b149b555621497a6cc0d46ac341b30bd9ec19eac7f3"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:25486eb223babe3eed4b8aecbac33b37e3dd6d776bc730ca14e1bf93888b979f"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:454db8a7ecfcf2ff6042dde58404164d969b6f5d58b926da15e6b23817950fc4"}, + {file = "tornado-6.4.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:a02a08cc7a9314b006f653ce40483b9b3c12cda222d6a46d4ac63bb6c9057698"}, + {file = "tornado-6.4.1-cp38-abi3-win32.whl", hash = "sha256:d9a566c40b89757c9aa8e6f032bcdb8ca8795d7c1a9762910c722b1635c9de4d"}, + {file = "tornado-6.4.1-cp38-abi3-win_amd64.whl", hash = "sha256:b24b8982ed444378d7f21d563f4180a2de31ced9d8d84443907a0a64da2072e7"}, + {file = "tornado-6.4.1.tar.gz", hash = "sha256:92d3ab53183d8c50f8204a51e6f91d18a15d5ef261e84d452800d4ff6fc504e9"}, +] + +[[package]] +name = "traitlets" +version = "5.14.3" +description = "Traitlets Python configuration system" +optional = false +python-versions = ">=3.8" +files = [ + {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, + {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, +] + +[package.extras] +docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] +test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] + +[[package]] +name = "typing-extensions" +version = "4.12.2" +description = "Backported and Experimental Type Hints for Python 3.8+" +optional = false +python-versions = ">=3.8" +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"}, +] + +[[package]] +name = "tzdata" +version = "2024.1" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.1-py2.py3-none-any.whl", hash = "sha256:9068bc196136463f5245e51efda838afa15aaeca9903f49050dfa2679db4d252"}, + {file = "tzdata-2024.1.tar.gz", hash = "sha256:2674120f8d891909751c38abcdfd386ac0a5a1127954fbc332af6b5ceae07efd"}, +] + +[[package]] +name = "urllib3" +version = "2.2.2" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.8" +files = [ + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "watchdog" +version = "4.0.1" +description = "Filesystem events monitoring" +optional = false +python-versions = ">=3.8" +files = [ + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:da2dfdaa8006eb6a71051795856bedd97e5b03e57da96f98e375682c48850645"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e93f451f2dfa433d97765ca2634628b789b49ba8b504fdde5837cdcf25fdb53b"}, + {file = "watchdog-4.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ef0107bbb6a55f5be727cfc2ef945d5676b97bffb8425650dadbb184be9f9a2b"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:17e32f147d8bf9657e0922c0940bcde863b894cd871dbb694beb6704cfbd2fb5"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:03e70d2df2258fb6cb0e95bbdbe06c16e608af94a3ffbd2b90c3f1e83eb10767"}, + {file = "watchdog-4.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:123587af84260c991dc5f62a6e7ef3d1c57dfddc99faacee508c71d287248459"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:093b23e6906a8b97051191a4a0c73a77ecc958121d42346274c6af6520dec175"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:611be3904f9843f0529c35a3ff3fd617449463cb4b73b1633950b3d97fa4bfb7"}, + {file = "watchdog-4.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:62c613ad689ddcb11707f030e722fa929f322ef7e4f18f5335d2b73c61a85c28"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d4925e4bf7b9bddd1c3de13c9b8a2cdb89a468f640e66fbfabaf735bd85b3e35"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cad0bbd66cd59fc474b4a4376bc5ac3fc698723510cbb64091c2a793b18654db"}, + {file = "watchdog-4.0.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:a3c2c317a8fb53e5b3d25790553796105501a235343f5d2bf23bb8649c2c8709"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c9904904b6564d4ee8a1ed820db76185a3c96e05560c776c79a6ce5ab71888ba"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:667f3c579e813fcbad1b784db7a1aaa96524bed53437e119f6a2f5de4db04235"}, + {file = "watchdog-4.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d10a681c9a1d5a77e75c48a3b8e1a9f2ae2928eda463e8d33660437705659682"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0144c0ea9997b92615af1d94afc0c217e07ce2c14912c7b1a5731776329fcfc7"}, + {file = "watchdog-4.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:998d2be6976a0ee3a81fb8e2777900c28641fb5bfbd0c84717d89bca0addcdc5"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e7921319fe4430b11278d924ef66d4daa469fafb1da679a2e48c935fa27af193"}, + {file = "watchdog-4.0.1-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:f0de0f284248ab40188f23380b03b59126d1479cd59940f2a34f8852db710625"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:bca36be5707e81b9e6ce3208d92d95540d4ca244c006b61511753583c81c70dd"}, + {file = "watchdog-4.0.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:ab998f567ebdf6b1da7dc1e5accfaa7c6992244629c0fdaef062f43249bd8dee"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_aarch64.whl", hash = "sha256:dddba7ca1c807045323b6af4ff80f5ddc4d654c8bce8317dde1bd96b128ed253"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_armv7l.whl", hash = "sha256:4513ec234c68b14d4161440e07f995f231be21a09329051e67a2118a7a612d2d"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_i686.whl", hash = "sha256:4107ac5ab936a63952dea2a46a734a23230aa2f6f9db1291bf171dac3ebd53c6"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64.whl", hash = "sha256:6e8c70d2cd745daec2a08734d9f63092b793ad97612470a0ee4cbb8f5f705c57"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_ppc64le.whl", hash = "sha256:f27279d060e2ab24c0aa98363ff906d2386aa6c4dc2f1a374655d4e02a6c5e5e"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_s390x.whl", hash = "sha256:f8affdf3c0f0466e69f5b3917cdd042f89c8c63aebdb9f7c078996f607cdb0f5"}, + {file = "watchdog-4.0.1-py3-none-manylinux2014_x86_64.whl", hash = "sha256:ac7041b385f04c047fcc2951dc001671dee1b7e0615cde772e84b01fbf68ee84"}, + {file = "watchdog-4.0.1-py3-none-win32.whl", hash = "sha256:206afc3d964f9a233e6ad34618ec60b9837d0582b500b63687e34011e15bb429"}, + {file = "watchdog-4.0.1-py3-none-win_amd64.whl", hash = "sha256:7577b3c43e5909623149f76b099ac49a1a01ca4e167d1785c76eb52fa585745a"}, + {file = "watchdog-4.0.1-py3-none-win_ia64.whl", hash = "sha256:d7b9f5f3299e8dd230880b6c55504a1f69cf1e4316275d1b215ebdd8187ec88d"}, + {file = "watchdog-4.0.1.tar.gz", hash = "sha256:eebaacf674fa25511e8867028d281e602ee6500045b57f43b08778082f7f8b44"}, +] + +[package.extras] +watchmedo = ["PyYAML (>=3.10)"] + +[[package]] +name = "wcwidth" +version = "0.2.13" +description = "Measures the displayed width of unicode strings in a terminal" +optional = false +python-versions = "*" +files = [ + {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, + {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, +] + +[[package]] +name = "webencodings" +version = "0.5.1" +description = "Character encoding aliases for legacy web content" +optional = false +python-versions = "*" +files = [ + {file = "webencodings-0.5.1-py2.py3-none-any.whl", hash = "sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78"}, + {file = "webencodings-0.5.1.tar.gz", hash = "sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "ce6ddcd0789cddc6c5e87f399754e6d8fc776df9b1b5419fe6a3a20faa5ea4a4" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 000000000..548e64293 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,26 @@ +[tool.poetry] +name = "langgraph-monorepo" +version = "0.0.1" +description = "LangGraph monorepo" +authors = ["Your Name "] +license = "MIT" +readme = "README.md" + +[tool.poetry.dependencies] +python = "^3.10" + +[tool.poetry.group.docs.dependencies] +langgraph = { path = "libs/langgraph/", develop = true } +mkdocs = "^1.6.0" +mkdocstrings = "^0.25.1" +mkdocstrings-python = "^1.10.4" +mkdocs-jupyter = "^0.24.7" +mkdocs-redirects = "^1.2.1" +mkdocs-minify-plugin = "^0.8.0" +mkdocs-rss-plugin = "^1.13.1" +mkdocs-git-committers-plugin-2 = "^2.3.0" +mkdocs-material = {extras = ["imaging"], version = "^9.5.27"} + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" From 79f0b4860d1601f54f0db4986861058bbbbc0672 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 10:56:45 -0400 Subject: [PATCH 15/27] attempt to fix js --- .github/workflows/ci.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ab25d72b1..fc0323504 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -34,7 +34,7 @@ strategy: matrix: working-directory: [ - "libs/langgraph/", + "libs/langgraph", "libs/sdk-py", "libs/cli" ] @@ -49,7 +49,7 @@ strategy: matrix: working-directory: [ - "libs/langgraph/", + "libs/langgraph", "libs/cli" ] uses: ./.github/workflows/_test.yml @@ -75,10 +75,13 @@ cache: "yarn" cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock - name: Install dependencies + working-directory: ${{ matrix.working-directory }} run: yarn install - name: Run lint + working-directory: ${{ matrix.working-directory }} run: yarn lint - name: Build + working-directory: ${{ matrix.working-directory }} run: yarn build ci_success: From 06f764f33def9b044c27bcc1d6ba4aa2f75f1cfb Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 11:00:15 -0400 Subject: [PATCH 16/27] add gitignore file --- .github/workflows/ci.yml | 3 --- libs/sdk-js/.gitignore | 8 ++++++++ 2 files changed, 8 insertions(+), 3 deletions(-) create mode 100644 libs/sdk-js/.gitignore diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fc0323504..baf705289 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -75,13 +75,10 @@ cache: "yarn" cache-dependency-path: ${{ matrix.working-directory }}/yarn.lock - name: Install dependencies - working-directory: ${{ matrix.working-directory }} run: yarn install - name: Run lint - working-directory: ${{ matrix.working-directory }} run: yarn lint - name: Build - working-directory: ${{ matrix.working-directory }} run: yarn build ci_success: diff --git a/libs/sdk-js/.gitignore b/libs/sdk-js/.gitignore new file mode 100644 index 000000000..8c9e5a99c --- /dev/null +++ b/libs/sdk-js/.gitignore @@ -0,0 +1,8 @@ +/client.cjs +/client.js +/client.d.ts +/client.d.cts +/index.cjs +/index.js +/index.d.ts +/index.d.cts From 4cdb64884d3cc8039e0440d9616636190ee5c465 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 11:17:48 -0400 Subject: [PATCH 17/27] merge latest libs --- libs/sdk-js/src/client.mts | 33 ---------- libs/sdk-js/src/index.mts | 1 - libs/sdk-js/src/schema.ts | 12 ---- libs/sdk-py/langgraph_sdk/client.py | 94 ++++++++++++++++++----------- libs/sdk-py/langgraph_sdk/schema.py | 21 ------- libs/sdk-py/pyproject.toml | 2 +- 6 files changed, 61 insertions(+), 102 deletions(-) diff --git a/libs/sdk-js/src/client.mts b/libs/sdk-js/src/client.mts index 3311daba5..6e49af778 100644 --- a/libs/sdk-js/src/client.mts +++ b/libs/sdk-js/src/client.mts @@ -6,7 +6,6 @@ import { GraphSchema, Metadata, Run, - RunEvent, Thread, ThreadState, } from "./schema.js"; @@ -643,38 +642,6 @@ class RunsClient extends BaseClient { return this.fetch(`/threads/${threadId}/runs/${runId}/join`); } - /** - * List all events for a run. - * - * @param threadId The ID of the thread. - * @param runId The ID of the run. - * @param options Filtering and pagination options. - * @returns List of events. - */ - async listEvents( - threadId: string, - runId: string, - options?: { - /** - * Maximum number of events to return. - * Defaults to 10 - */ - limit?: number; - /** - * Offset to start from. - * Defaults to 0. - */ - offset?: number; - }, - ): Promise { - return this.fetch(`/threads/${threadId}/runs/${runId}/events`, { - params: { - limit: options?.limit ?? 10, - offset: options?.offset ?? 0, - }, - }); - } - /** * Delete a run. * diff --git a/libs/sdk-js/src/index.mts b/libs/sdk-js/src/index.mts index b420f7df8..bb7359349 100644 --- a/libs/sdk-js/src/index.mts +++ b/libs/sdk-js/src/index.mts @@ -8,7 +8,6 @@ export type { GraphSchema, Metadata, Run, - RunEvent, Thread, ThreadState, } from "./schema.js"; diff --git a/libs/sdk-js/src/schema.ts b/libs/sdk-js/src/schema.ts index b8d16cd2a..9594595eb 100644 --- a/libs/sdk-js/src/schema.ts +++ b/libs/sdk-js/src/schema.ts @@ -94,15 +94,3 @@ export interface Run { | "interrupted"; metadata: Metadata; } - -export interface RunEvent { - event_id: string; - run_id: string; - received_at: string; - span_id: string; - event: string; - name: string; - data: Record; - metadata: Record; - tags: string[]; -} diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index d07094c61..8c753f3ab 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -19,7 +19,6 @@ from langgraph_sdk.schema import ( Metadata, MultitaskStrategy, Run, - RunEvent, StreamMode, Thread, ThreadState, @@ -231,11 +230,13 @@ class AssistantsClient: assistant_id: Optional[str] = None, ) -> Assistant: """Create a new assistant.""" - payload = { - "metadata": metadata, + payload: Dict[str, Any] = { "graph_id": graph_id, - "config": config or {}, } + if config: + payload["config"] = config + if metadata: + payload["metadata"] = metadata if assistant_id: payload["assistant_id"] = assistant_id return await self.http.post("/assistants", json=payload) @@ -249,9 +250,16 @@ class AssistantsClient: metadata: Metadata = None, ) -> Assistant: """Update an assistant.""" + payload: Dict[str, Any] = {} + if graph_id: + payload["graph_id"] = graph_id + if config: + payload["config"] = config + if metadata: + payload["metadata"] = metadata return await self.http.patch( f"/assistants/{assistant_id}", - json={"metadata": metadata, "graph_id": graph_id, "config": config}, + json=payload, ) async def delete( @@ -264,10 +272,16 @@ class AssistantsClient: async def search( self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0 ) -> list[Assistant]: + payload: Dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata """Search for assistants.""" return await self.http.post( "/assistants/search", - json={"metadata": metadata, "limit": limit, "offset": offset}, + json=payload, ) @@ -286,12 +300,14 @@ class ThreadsClient: thread_id: Optional[str] = None, ) -> Thread: """Create a new thread.""" - payload: Dict[str, Any] = {"metadata": metadata} + payload: Dict[str, Any] = {} if thread_id: payload["thread_id"] = thread_id + if metadata: + payload["metadata"] = metadata return await self.http.post("/threads", json=payload) - async def update(self, thread_id: str, *, metadata: Metadata = None) -> Thread: + async def update(self, thread_id: str, *, metadata: dict[str, Any]) -> Thread: """Update a thread.""" return await self.http.patch( f"/threads/{thread_id}", json={"metadata": metadata} @@ -305,9 +321,15 @@ class ThreadsClient: self, *, metadata: Metadata = None, limit: int = 10, offset: int = 0 ) -> list[Thread]: """Search for threads.""" + payload: Dict[str, Any] = { + "limit": limit, + "offset": offset, + } + if metadata: + payload["metadata"] = metadata return await self.http.post( "/threads/search", - json={"metadata": metadata, "limit": limit, "offset": offset}, + json=payload, ) async def get_state( @@ -328,10 +350,14 @@ class ThreadsClient: checkpoint_id: Optional[str] = None, ) -> None: """Update the state of a thread.""" - return await self.http.post( - f"/threads/{thread_id}/state", - json={"values": values, "checkpoint_id": checkpoint_id, "as_node": as_node}, - ) + payload: Dict[str, Any] = { + "values": values, + } + if checkpoint_id: + payload["checkpoint_id"] = checkpoint_id + if as_node: + payload["as_node"] = as_node + return await self.http.post(f"/threads/{thread_id}/state", json=payload) async def patch_state( self, @@ -356,10 +382,14 @@ class ThreadsClient: metadata: Optional[dict] = None, ) -> list[ThreadState]: """Get the history of a thread.""" - return await self.http.post( - f"/threads/{thread_id}/history", - json={"limit": limit, "before": before, "metadata": metadata}, - ) + payload: Dict[str, Any] = { + "limit": limit, + } + if before: + payload["before"] = before + if metadata: + payload["metadata"] = metadata + return await self.http.post(f"/threads/{thread_id}/history", json=payload) class RunsClient: @@ -426,16 +456,16 @@ class RunsClient: "interrupt_after": interrupt_after, "feedback_keys": feedback_keys, "checkpoint_id": checkpoint_id, + "multitask_strategy": multitask_strategy, } - if multitask_strategy: - payload["multitask_strategy"] = multitask_strategy - endpoint = ( f"/threads/{thread_id}/runs/stream" if thread_id is not None else "/runs/stream" ) - return self.http.stream(endpoint, "POST", json=payload) + return self.http.stream( + endpoint, "POST", json={k: v for k, v in payload.items() if v is not None} + ) @overload async def create( @@ -493,9 +523,9 @@ class RunsClient: "interrupt_after": interrupt_after, "webhook": webhook, "checkpoint_id": checkpoint_id, + "multitask_strategy": multitask_strategy, } - if multitask_strategy: - payload["multitask_strategy"] = multitask_strategy + payload = {k: v for k, v in payload.items() if v is not None} if thread_id: return await self.http.post(f"/threads/{thread_id}/runs", json=payload) else: @@ -553,20 +583,22 @@ class RunsClient: "interrupt_before": interrupt_before, "interrupt_after": interrupt_after, "checkpoint_id": checkpoint_id, + "multitask_strategy": multitask_strategy, } - if multitask_strategy: - payload["multitask_strategy"] = multitask_strategy - endpoint = ( f"/threads/{thread_id}/runs/wait" if thread_id is not None else "/runs/wait" ) - return await self.http.post(endpoint, json=payload) + return await self.http.post( + endpoint, json={k: v for k, v in payload.items() if v is not None} + ) async def list( self, thread_id: str, *, limit: int = 10, offset: int = 0 ) -> List[Run]: """List runs.""" - return await self.http.get(f"/threads/{thread_id}/runs") + return await self.http.get( + f"/threads/{thread_id}/runs?limit={limit}&offset={offset}" + ) async def get(self, thread_id: str, run_id: str) -> Run: """Get a run.""" @@ -583,12 +615,6 @@ class RunsClient: """Block until a run is done.""" return await self.http.get(f"/threads/{thread_id}/runs/{run_id}/join") - async def list_events( - self, thread_id: str, run_id: str, *, limit: int = 10, offset: int = 0 - ) -> List[RunEvent]: - """List run events.""" - return await self.http.get(f"/threads/{thread_id}/runs/{run_id}/events") - async def delete(self, thread_id: str, run_id: str) -> None: """Delete a run.""" await self.http.delete(f"/threads/{thread_id}/runs/{run_id}") diff --git a/libs/sdk-py/langgraph_sdk/schema.py b/libs/sdk-py/langgraph_sdk/schema.py index dc1097183..63423ff4c 100644 --- a/libs/sdk-py/langgraph_sdk/schema.py +++ b/libs/sdk-py/langgraph_sdk/schema.py @@ -105,24 +105,3 @@ class Run(TypedDict): """The status of the run. One of 'pending', 'running', 'error', 'success'.""" metadata: Metadata """The run metadata.""" - - -class RunEvent(TypedDict): - event_id: str - """The ID of the event.""" - run_id: str - """The ID of the run.""" - received_at: datetime - """The time the event was received.""" - span_id: str - """The ID of the span.""" - event: str - """The event type.""" - name: str - """The event name.""" - data: dict - """The event data.""" - metadata: dict - """The event metadata.""" - tags: list[str] - """The event tags.""" diff --git a/libs/sdk-py/pyproject.toml b/libs/sdk-py/pyproject.toml index f6fb8ae94..d3c25564a 100644 --- a/libs/sdk-py/pyproject.toml +++ b/libs/sdk-py/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-sdk" -version = "0.1.20" +version = "0.1.21" description = "" authors = ["Nuno Campos "] readme = "README.md" From 2b0fcb26f9ccda3cbec9b1d91ef8e27175a68b72 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 11:30:17 -0400 Subject: [PATCH 18/27] bump deps --- libs/langgraph/poetry.lock | 307 +++++++++++++++++++------------------ 1 file changed, 156 insertions(+), 151 deletions(-) diff --git a/libs/langgraph/poetry.lock b/libs/langgraph/poetry.lock index ef758aca3..10e656b8a 100644 --- a/libs/langgraph/poetry.lock +++ b/libs/langgraph/poetry.lock @@ -138,12 +138,13 @@ files = [ [[package]] name = "anthropic" -version = "0.28.0" +version = "0.28.1" description = "The official Python library for the anthropic API" optional = false python-versions = ">=3.7" files = [ - {file = "anthropic-0.28.0-py3-none-any.whl", hash = "sha256:2b620b21aee3d20c5d8005483c34df239d53ae895687113b26b8a36892a7e20f"}, + {file = "anthropic-0.28.1-py3-none-any.whl", hash = "sha256:c4773ae2b42951a6b747bed328b0d03fa412938c95c3a8b9dce70d69badb710b"}, + {file = "anthropic-0.28.1.tar.gz", hash = "sha256:e3a6d595bde241141bdc685edc393903ec95c7fa378013a71186cfb8f32b1793"}, ] [package.dependencies] @@ -762,13 +763,13 @@ tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipyth [[package]] name = "fastjsonschema" -version = "2.19.1" +version = "2.20.0" description = "Fastest Python implementation of JSON schema" optional = false python-versions = "*" files = [ - {file = "fastjsonschema-2.19.1-py3-none-any.whl", hash = "sha256:3672b47bc94178c9f23dbb654bf47440155d4db9df5f7bc47643315f9c405cd0"}, - {file = "fastjsonschema-2.19.1.tar.gz", hash = "sha256:e3126a94bdc4623d3de4485f8d468a12f02a67921315ddc87836d6e456dc789d"}, + {file = "fastjsonschema-2.20.0-py3-none-any.whl", hash = "sha256:5875f0b0fa7a0043a91e93a9b8f793bcbbba9691e7fd83dca95c28ba26d21f0a"}, + {file = "fastjsonschema-2.20.0.tar.gz", hash = "sha256:3d48fc5300ee96f5d116f10fe6f28d938e6008f59a6a025c2649475b87f76a23"}, ] [package.extras] @@ -776,18 +777,18 @@ devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benc [[package]] name = "filelock" -version = "3.14.0" +version = "3.15.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.14.0-py3-none-any.whl", hash = "sha256:43339835842f110ca7ae60f1e1c160714c5a6afd15a2873419ab185334975c0f"}, - {file = "filelock-3.14.0.tar.gz", hash = "sha256:6ea72da3be9b8c82afd3edcf99f2fffbb5076335a5ae4d03248bb5b6c3eae78a"}, + {file = "filelock-3.15.1-py3-none-any.whl", hash = "sha256:71b3102950e91dfc1bb4209b64be4dc8854f40e5f534428d8684f953ac847fac"}, + {file = "filelock-3.15.1.tar.gz", hash = "sha256:58a2549afdf9e02e10720eaa4d4470f56386d7a6f72edd7d0596337af8ed7ad8"}, ] [package.extras] docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.25.2)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8.0.1)", "pytest (>=7.4.3)", "pytest-asyncio (>=0.21)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] typing = ["typing-extensions (>=4.8)"] [[package]] @@ -1072,13 +1073,13 @@ socks = ["socksio (==1.*)"] [[package]] name = "huggingface-hub" -version = "0.23.3" +version = "0.23.4" description = "Client library to download and publish models, datasets and other repos on the huggingface.co hub" optional = false python-versions = ">=3.8.0" files = [ - {file = "huggingface_hub-0.23.3-py3-none-any.whl", hash = "sha256:22222c41223f1b7c209ae5511d2d82907325a0e3cdbce5f66949d43c598ff3bc"}, - {file = "huggingface_hub-0.23.3.tar.gz", hash = "sha256:1a1118a0b3dea3bab6c325d71be16f5ffe441d32f3ac7c348d6875911b694b5b"}, + {file = "huggingface_hub-0.23.4-py3-none-any.whl", hash = "sha256:3a0b957aa87150addf0cc7bd71b4d954b78e749850e1e7fb29ebbd2db64ca037"}, + {file = "huggingface_hub-0.23.4.tar.gz", hash = "sha256:35d99016433900e44ae7efe1c209164a5a81dbbcd53a52f99c281dcd7ce22431"}, ] [package.dependencies] @@ -1288,72 +1289,72 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.4.1" +version = "0.4.2" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" files = [ - {file = "jiter-0.4.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:3c2370cd8826b484f3fc6ed729cb58510ba24b4bc277c92323a57d35cf4df223"}, - {file = "jiter-0.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3587af23140a2eb282bba980010dae60f3b8b1579a034c5e869e9b94220a5972"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df8788d34545d47de864032a78bae49a14b66b67196c73cd95f1c1e3081d9c73"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:91bf2d31e906a3ca26fc8ee0cb979e0e51b12aa7e83999c6afea047538f95e5c"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8586e68702666b6acd919c65f718a09603adcfd8b4c7026bade2441d9e7bd34e"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:639b766bde088546b5205fd31608502b5b42abee3294b43cc95c6ea8f9a257c3"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5cb32457296351c98da289d21a092a6c53c75beb80e7127c8e16224ee342c7c7"}, - {file = "jiter-0.4.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:583263bd81bce5426806cf27ba85e4b97746797fae13c71e50a8689e06e57f81"}, - {file = "jiter-0.4.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c0e413999a819ccef9b5fd22ef4b9b8c48a98e49da4d09b43ebce286d0d80e26"}, - {file = "jiter-0.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5e50468d5acfef335ba8bc3892bb304354c38ba18acb3f7ae428451e47136e49"}, - {file = "jiter-0.4.1-cp310-none-win32.whl", hash = "sha256:b2ac90b94dd717644c61c8ed0c2ec6e9505bd7314b91a1549680d7f1cb8f1da4"}, - {file = "jiter-0.4.1-cp310-none-win_amd64.whl", hash = "sha256:2509868b8dacf4f65d04b4d951d390f30f403a87a997a14e2db2d232c7a468a7"}, - {file = "jiter-0.4.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:b56e4f2fa5767976f2332e9e067010ddfe1379b6456b5458123ba50657c33e02"}, - {file = "jiter-0.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f813b49db21c946aa010accc54b8e5c9d0007be252bda4738159fa6c65d6d396"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c2933c04ebd77b3e9cf34f80ba45c093739c687c9c5a4fd0a8c701a3bfd90940"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b02ddd65513705ec38211ea48ffc0fde41aa46166d9f7706972daf97b57c8599"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:88d06af883524e5429d75395bb4ee6ddeda4c30818b2f3e3b8f4afa2dd8f28c0"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd333eca1090cf21e6359721eecbb2a7fe031cc4db3dd595081430b4a59371c5"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdc90017cd22dca6b40f2f8518b38363e78aee3cb32f84e1cb08900a598ca91b"}, - {file = "jiter-0.4.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:aedce5b11ca58853d46461e1880079836bfab4e132be2b7d2093ec193081bbc8"}, - {file = "jiter-0.4.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e55b2f4d2d5066979b0e0e58d85e3fffd0f6e6a0523aab7e0ce75950259387da"}, - {file = "jiter-0.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b3c85c586f1cd71c2a1e78756f6857119947b532379bd9be4338bf3dacf1e87f"}, - {file = "jiter-0.4.1-cp311-none-win32.whl", hash = "sha256:37875f56222f2bb61410e15196d9b91510ccca322c391f3d20c91d667130d15e"}, - {file = "jiter-0.4.1-cp311-none-win_amd64.whl", hash = "sha256:b71758befea8dbdc10e0fb40a776e085eed0e74afef42468ebb58562289e9190"}, - {file = "jiter-0.4.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93a8869c18a3721e41d7adb289c5c71aea8887eb368a3411219a0afb62955cbe"}, - {file = "jiter-0.4.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0ffbc61349f2f27676d40d68e8ef83fc2a9dd2c1464962b1d1b1d8504bccbf85"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b5f1f33e9fd4de4369a8d00fdf2571a8246a942095fb2a9d4cd25135ee675c85"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d8f91a19eba23b4a1bb1e5b64c19cfdbf46604180e5dee40548b53ca13afd2d9"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2a60f8e495448d8e02d291fa9a8522cfe775a10210ba428994f383965e6f6e65"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7387998c6585ce0f02ae4f5338fabf72b99494860c347f27bc34720290eafb15"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c7cbf41da6506b42db21a1a0befa48e16384591e84e80db002a826ccf07668f1"}, - {file = "jiter-0.4.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:793ae2499722b9fc31e300abd07418902512109bca17f617598a31a9e17bddce"}, - {file = "jiter-0.4.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:19f7953b8ada7ee109764ad91d4afb1a9f69b77cde0b890844744c513612dbf8"}, - {file = "jiter-0.4.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:dcd3d6a142d7b267a8c5f1e28d02759e2e29343b095f6d8aaf463333a842e1f8"}, - {file = "jiter-0.4.1-cp312-none-win32.whl", hash = "sha256:fffdf137c3ab7f0c5facb7c478b57ad3e1eb9b149daff48687844de77b78ab70"}, - {file = "jiter-0.4.1-cp312-none-win_amd64.whl", hash = "sha256:fde004e47a801512c4167f188a6372960374fbd59e635753b3ee536e81953eb3"}, - {file = "jiter-0.4.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:b429ba25e05ca28d5e7efa4249032746ac28ec6ad68017ed3ea009989c597911"}, - {file = "jiter-0.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:27df9925d0282c80bdd41613ace7cd799bd6355acdfe25cc48ec16843541999e"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eb68736a0e2b00eda83937c1937f999e8d7dab68820c04343ac2e2eb2c5c2193"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c218458ac32ce0b495f013293867649b40c067a4d7533fa0d70a46f7194febae"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ebead86e80e352753f6e6f78ca96c12d764a8dbbc7c4b25938ce657ab0e4e879"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5bf58f878d43294bea400a9df86ef7796dd2e67969109bce22d337ca77372c69"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba671e60570cd99b8ed83ce0d82703040dc34c793229ac607f09683ba1981163"}, - {file = "jiter-0.4.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ef0bd8b68ad14f045544989b6ad3758bee6dc01f6924bce5b4fd7060b0a09b1b"}, - {file = "jiter-0.4.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:7888f165a0fe285e015ee18cfcb8b5432c4fa389235b4c24c339ca0cc51ba979"}, - {file = "jiter-0.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:7d9c443b2a71a8c3ab6578f5faf7725ad5f63dbb92d87f820eec56de9da0560f"}, - {file = "jiter-0.4.1-cp38-none-win32.whl", hash = "sha256:6f618d1b04493bc9196e466ef59e0a6388eb85e936d1a61833449677643bbdd9"}, - {file = "jiter-0.4.1-cp38-none-win_amd64.whl", hash = "sha256:46b6364a0b2a81cc259768bda131e8528aa3af4312f23f7e10aa04d24f54bbb1"}, - {file = "jiter-0.4.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6680785a9273a87e463c86a962042d620c00c7bb8100dde1a4c78b2184cdd613"}, - {file = "jiter-0.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:36b10d945b9ccd2e9f2720e37395daf9e63cfa47e5e0e2887c4931888f0800cd"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78820599693bda34be17119abf9fad1f02e501b4816e47addbee9c5c768fb361"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68697317170d8f851dfe978ba278b886e54e837ecd2a80c4a33ae780a0f19526"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d126ffc3876cfc1fba6ae2be37f2532b5db593a96cf4b845724b50b44339c4fd"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b082223f2e7e6f506d837df935f58f25cabf0a2b35902b4ec73fb561fbf2694a"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13314287782782be8439dfafca50f13fcab18046227068a3a8e8d8ac888f092b"}, - {file = "jiter-0.4.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3da1346375605926f1ca4604d154ff41f5e3b933c6e01005e534bca2197d919f"}, - {file = "jiter-0.4.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9b67a97fbce3ec35ee97439c8b786393f71ecbe7458d5e9279d4c172772eac36"}, - {file = "jiter-0.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:7b0f34544923bff0f3393aa3d60087686d86089c9361f6530bb5d19ebfb3db47"}, - {file = "jiter-0.4.1-cp39-none-win32.whl", hash = "sha256:b0c93ef95b896a4ce5edff23071e4dcad77c9e9262fcb6ca2b050f781e8335a9"}, - {file = "jiter-0.4.1-cp39-none-win_amd64.whl", hash = "sha256:3db5c83c8655ce031943b6f08434dac1a91e1477b0df452de0c44f3390a9b22c"}, - {file = "jiter-0.4.1.tar.gz", hash = "sha256:741851cf5f37cf3583f2a56829d734c9fd17334770c9a326e6d25291603d4278"}, + {file = "jiter-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c2b003ff58d14f5e182b875acd5177b2367245c19a03be9a2230535d296f7550"}, + {file = "jiter-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b48c77c25f094707731cd5bad6b776046846b60a27ee20efc8fadfb10a89415f"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f50ad6b172bde4d45f4d4ea10c49282a337b8bb735afc99763dfa55ea84a743"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95f6001e86f525fbbc9706db2078dc22be078b0950de55b92d37041930f5f940"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16646ef23b62b007de80460d303ebb2d81e355dac9389c787cec87cdd7ffef2f"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b4e847c13b0bf1255c711a92330e7a8cb8b5cdd1e37d7db309627bcdd3367ff"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c536589be60e4c5f2b20fadc4db7e9f55d4c9df3551f29ddf1c4a18dcc9dd54"}, + {file = "jiter-0.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3b2763996167830889a854b4ded30bb90897f9b76be78069c50c3ec4540950e"}, + {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:675e8ab98c99495091af6b6e9bf2b6353bcf81f25ab6ce27d36127e315b4505d"}, + {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e48e43d9d999aaf55f53406b8846ff8cbe3e47ee4b9dc37e5a10a65ce760809f"}, + {file = "jiter-0.4.2-cp310-none-win32.whl", hash = "sha256:881b6e67c50bc36acb3570eda693763c8cd77d590940e06fa6d325d0da52ec1b"}, + {file = "jiter-0.4.2-cp310-none-win_amd64.whl", hash = "sha256:bb8f7b43259efc6add0d721ade2953e064b24e2026d26d979bc09ec080844cef"}, + {file = "jiter-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:24ad336ac47f274fa83f6fbedcabff9d3387c80f67c66b992688e6a8ba2c47e9"}, + {file = "jiter-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fc392a220095730afe365ce1516f2f88bb085a2fd29ea191be9c6e3c71713d9a"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1fdc408de36c81460896de0176f2f7b9f3574dcd35693a0b2c00f4ca34c98e4"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10ad76722ee6a8c820b0db06a793c08b7d679e5201b9563015bd1e06c959a09"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbb46d1e9c82bba87f0cbda38413e49448a7df35b1e55917124bff9f38974a23"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:194e28ef4b5f3b61408cb2ee6b6dcbcdb0c9063d01b92b01345b7605692849f5"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0a447533eccd62748a727e058efa10a8d7cf1de8ffe1a4d705ecb41dad9090"}, + {file = "jiter-0.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5f7704d7260bbb88cca3453951af739589132b26e896a3144fa2dae2263716d7"}, + {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:01427458bc9550f2eda09d425755330e7d0eb09adce099577433bebf05d28d59"}, + {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:159b8416879c0053b17c352f70b67b749ef5b2924c6154318ecf71918aab0905"}, + {file = "jiter-0.4.2-cp311-none-win32.whl", hash = "sha256:f2445234acfb79048ce1a0d5d0e181abb9afd9e4a29d8d9988fe26cc5773a81a"}, + {file = "jiter-0.4.2-cp311-none-win_amd64.whl", hash = "sha256:e15a65f233b6b0e5ac10ddf3b97ceb18aa9ffba096259961641d78b4ee321bd5"}, + {file = "jiter-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d61d59521aea9745447ce50f74d39a16ef74ec9d6477d9350d77e75a3d774ad2"}, + {file = "jiter-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eef607dc0acc251923427808dbd017f1998ae3c1a0430a261527aa5cbb3a942"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af6bf39954646e374fc47429c656372ac731a6a26b644158a5a84bcdbed33a47"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f509d23606e476852ee46a2b65b5c4ad3905f17424d9cc19c1dffa1c94ba3c6"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59672774daa44ee140aada0c781c82bee4d9ac5e522966186cfb6b3c217d8a51"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24a0458efac5afeca254cf557b8a654e17013075a69905c78f88d557f129d871"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8860766d1c293e75c1bb4e25b74fa987e3adf199cac3f5f9e6e49c2bebf092f"}, + {file = "jiter-0.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a109f3281b72bbf4921fe43db1005c004a38559ca0b6c4985add81777dfe0a44"}, + {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:faa7e667454b77ad2f0ef87db39f4944de759617aadf210ea2b73f26bb24755f"}, + {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3512f8b00cafb6780b427cb6282800d2bf8277161d9c917830661bd4ed1d3528"}, + {file = "jiter-0.4.2-cp312-none-win32.whl", hash = "sha256:853b35d508ee5b66d06630473c1c0b7bb5e29bf4785c9d2202437116c94f7e21"}, + {file = "jiter-0.4.2-cp312-none-win_amd64.whl", hash = "sha256:4a3a8197784278eb8b24cb02c45e1cad67c2ce5b5b758adfb19b87f74bbdff9c"}, + {file = "jiter-0.4.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ca2a4d750aed3154b89f2efb148609fc985fad8db739460797aaf9b478acedda"}, + {file = "jiter-0.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0e6c304b3cc6896256727e1fb8991c7179a345eca8224e201795e9cacf4683b0"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cc34ac708ae1750d077e490321761ec4b9a055b994cbdd1d6fbd37099e4aa7b"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8c93383875ab8d2e4f760aaff335b4a12ff32d4f9cf49c4498d657734f611466"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce197ee044add576afca0955b42142dd0312639adb6ebadbdbe4277f2855614f"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a427716813ff65480ca5b5117cfa099f49b49cd38051f8609bd0d5493013ca0"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479990218353356234669e70fac53e5eb6f739a10db25316171aede2c97d9364"}, + {file = "jiter-0.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d35a91ec5ac74cf33234c431505299fa91c0a197c2dbafd47400aca7c69489d4"}, + {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b27189847193708c94ad10ca0d891309342ae882725d2187cf5d2db02bde8d1b"}, + {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76c255308cd1093fb411a03756b7bb220e48d4a98c30cbc79ed448bf3978e27d"}, + {file = "jiter-0.4.2-cp38-none-win32.whl", hash = "sha256:bb77438060bad49cc251941e6701b31138365c8a0ddaf10cdded2fcc6dd30701"}, + {file = "jiter-0.4.2-cp38-none-win_amd64.whl", hash = "sha256:ce858af19f7ce0d4b51c9f6c0c9d08f1e9dcef1986c5875efd0674a7054292ca"}, + {file = "jiter-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6128838a2f357b3921b2a3242d5dc002ae4255ecc8f9f05c20d56d7d2d79c5ad"}, + {file = "jiter-0.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f2420cebb9ba856cb57dcab1d2d8def949b464b0db09c22a4e4dbd52fff7b200"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d13d8128e853b320e00bb18bd4bb8b136cc0936091dc87633648fc688eb705"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eba5d6e54f149c508ba88677f97d3dc7dd75e9980d234bbac8027ac6db0763a3"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fad5d64af0bc0545237419bf4150d8de56f0bd217434bdd1a59730327252bef"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d179e7bca89cf5719bd761dd37a341ff0f98199ecaa9c14af09792e47e977cc"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36353caee9f103d8ee7bda077f6400505b0f370e27eabcab33a33d21de12a2a6"}, + {file = "jiter-0.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dd146c25bce576ca5db64fc7eccb8862af00f1f0e30108796953f12a53660e4c"}, + {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:14b7c08cadbcd703041c66dc30e24e17de2f340281cac0e69374223ecf153aa4"}, + {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a90f1a8b3d29aea198f8ea2b01148276ced8056e5103f32525266b3d880e65c9"}, + {file = "jiter-0.4.2-cp39-none-win32.whl", hash = "sha256:25b174997c780337b61ae57b1723455eecae9a17a9659044fd3c3b369190063f"}, + {file = "jiter-0.4.2-cp39-none-win_amd64.whl", hash = "sha256:bef62cea18521c5b99368147040c7e560c55098a35c93456f110678a2d34189a"}, + {file = "jiter-0.4.2.tar.gz", hash = "sha256:29b9d44f23f0c05f46d482f4ebf03213ee290d77999525d0975a17f875bf1eea"}, ] [[package]] @@ -1702,22 +1703,25 @@ files = [ [[package]] name = "langchain" -version = "0.2.3" +version = "0.2.5" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.3-py3-none-any.whl", hash = "sha256:5dc33cd9c8008693d328b7cb698df69073acecc89ad9c2a95f243b3314f8d834"}, - {file = "langchain-0.2.3.tar.gz", hash = "sha256:81962cc72cce6515f7bd71e01542727870789bf8b666c6913d85559080c1a201"}, + {file = "langchain-0.2.5-py3-none-any.whl", hash = "sha256:9aded9a65348254e1c93dcdaacffe4d1b6a5e7f74ef80c160c88ff78ad299228"}, + {file = "langchain-0.2.5.tar.gz", hash = "sha256:ffdbf4fcea46a10d461bcbda2402220fcfd72a0c70e9f4161ae0510067b9b3bd"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" async-timeout = {version = ">=4.0.0,<5.0.0", markers = "python_version < \"3.11\""} -langchain-core = ">=0.2.0,<0.3.0" +langchain-core = ">=0.2.7,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" -numpy = ">=1,<2" +numpy = [ + {version = ">=1,<2", markers = "python_version < \"3.12\""}, + {version = ">=1.26.0,<2.0.0", markers = "python_version >= \"3.12\""}, +] pydantic = ">=1,<3" PyYAML = ">=5.3" requests = ">=2,<3" @@ -1742,13 +1746,13 @@ langchain-core = ">=0.2.2rc1,<0.3" [[package]] name = "langchain-core" -version = "0.2.7" +version = "0.2.8" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.2.7-py3-none-any.whl", hash = "sha256:fd02e153c898486dd728d634684ffc64bc257ff2ba443dc7e53d017ac0bf4658"}, - {file = "langchain_core-0.2.7.tar.gz", hash = "sha256:b0b1b6dfbdedb39426fcb8bd3f07e40eec7964856e3fc384c420ca6dba61b34e"}, + {file = "langchain_core-0.2.8-py3-none-any.whl", hash = "sha256:172c81c858dc1f3123cc72b7e44e10f44c92f8a761cae18c364081f6c208e9f6"}, + {file = "langchain_core-0.2.8.tar.gz", hash = "sha256:2db866a4514672c4875b69d5590aa2ed50aa0d144874268bef68d74b5e7f33f9"}, ] [package.dependencies] @@ -1794,28 +1798,29 @@ extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] [[package]] name = "langchainhub" -version = "0.1.18" +version = "0.1.20" description = "The LangChain Hub API client" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchainhub-0.1.18-py3-none-any.whl", hash = "sha256:11501f15e7f34715ecc8892587daa35c6f2a3005e1f2926c9bcabd31fc2c100c"}, - {file = "langchainhub-0.1.18.tar.gz", hash = "sha256:f2d0d8bf3abe4ca5e70511d8220bdc9ccea28d5267bcfd0e5ef9c53bd5bd3bad"}, + {file = "langchainhub-0.1.20-py3-none-any.whl", hash = "sha256:b3cbb5b2d7d6f9c3f89748bcc74424d8030ed4ebca58b5f44e0b6d9f111e33eb"}, + {file = "langchainhub-0.1.20.tar.gz", hash = "sha256:499fa8958233071f35750987f325005d16241bebd455163955b607c195c37f25"}, ] [package.dependencies] +packaging = ">=23.2,<25" requests = ">=2,<3" types-requests = ">=2.31.0.2,<3.0.0.0" [[package]] name = "langsmith" -version = "0.1.77" +version = "0.1.79" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.77-py3-none-any.whl", hash = "sha256:2202cc21b1ed7e7b9e5d2af2694be28898afa048c09fdf09f620cbd9301755ae"}, - {file = "langsmith-0.1.77.tar.gz", hash = "sha256:4ace09077a9a4e412afeb4b517ca68e7de7b07f36e4792dc8236ac5207c0c0c7"}, + {file = "langsmith-0.1.79-py3-none-any.whl", hash = "sha256:c7f2c23981917713b5515b773f37c84ff68a7adf803476e2ebb5adcb36a04202"}, + {file = "langsmith-0.1.79.tar.gz", hash = "sha256:d215718cfdcdf4a011126b7a3d4a37eee96d887e59ac1e628a57e24b2bfa3163"}, ] [package.dependencies] @@ -2272,13 +2277,13 @@ files = [ [[package]] name = "openai" -version = "1.33.0" +version = "1.34.0" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.33.0-py3-none-any.whl", hash = "sha256:621163b56570897ab8389d187f686a53d4771fd6ce95d481c0a9611fe8bc4229"}, - {file = "openai-1.33.0.tar.gz", hash = "sha256:1169211a7b326ecbc821cafb427c29bfd0871f9a3e0947dd9e51acb3b0f1df78"}, + {file = "openai-1.34.0-py3-none-any.whl", hash = "sha256:018623c2f795424044675c6230fa3bfbf98d9e0aab45d8fd116f2efb2cfb6b7e"}, + {file = "openai-1.34.0.tar.gz", hash = "sha256:95c8e2da4acd6958e626186957d656597613587195abd0fb2527566a93e76770"}, ] [package.dependencies] @@ -2295,57 +2300,57 @@ datalib = ["numpy (>=1)", "pandas (>=1.2.3)", "pandas-stubs (>=1.1.0.11)"] [[package]] name = "orjson" -version = "3.10.4" +version = "3.10.5" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" optional = false python-versions = ">=3.8" files = [ - {file = "orjson-3.10.4-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:afca963f19ca60c7aedadea9979f769139127288dd58ccf3f7c5e8e6dc62cabf"}, - {file = "orjson-3.10.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b112eff36ba7ccc7a9d6b87e17b9d6bde4312d05e3ddf66bf5662481dee846"}, - {file = "orjson-3.10.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:02b192eaba048b1039eca9a0cef67863bd5623042f5c441889a9957121d97e14"}, - {file = "orjson-3.10.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:827c3d0e4fc44242c82bfdb1a773235b8c0575afee99a9fa9a8ce920c14e440f"}, - {file = "orjson-3.10.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca8ec09724f10ec209244caeb1f9f428b6bb03f2eda9ed5e2c4dd7f2b7fabd44"}, - {file = "orjson-3.10.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:8eaa5d531a8fde11993cbcb27e9acf7d9c457ba301adccb7fa3a021bfecab46c"}, - {file = "orjson-3.10.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:e112aa7fc4ea67367ec5e86c39a6bb6c5719eddc8f999087b1759e765ddaf2d4"}, - {file = "orjson-3.10.4-cp310-none-win32.whl", hash = "sha256:1538844fb88446c42da3889f8c4ecce95a630b5a5ba18ecdfe5aea596f4dff21"}, - {file = "orjson-3.10.4-cp310-none-win_amd64.whl", hash = "sha256:de02811903a2e434127fba5389c3cc90f689542339a6e52e691ab7f693407b5a"}, - {file = "orjson-3.10.4-cp311-cp311-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:358afaec75de7237dfea08e6b1b25d226e33a1e3b6dc154fc99eb697f24a1ffa"}, - {file = "orjson-3.10.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb4e292c3198ab3d93e5f877301d2746be4ca0ba2d9c513da5e10eb90e19ff52"}, - {file = "orjson-3.10.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5c39e57cf6323a39238490092985d5d198a7da4a3be013cc891a33fef13a536e"}, - {file = "orjson-3.10.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f86df433fc01361ff9270ad27455ce1ad43cd05e46de7152ca6adb405a16b2f6"}, - {file = "orjson-3.10.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c9966276a2c97e93e6cbe8286537f88b2a071827514f0d9d47a0aefa77db458"}, - {file = "orjson-3.10.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:c499a14155a1f5a1e16e0cd31f6cf6f93965ac60a0822bc8340e7e2d3dac1108"}, - {file = "orjson-3.10.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3087023ce904a327c29487eb7e1f2c060070e8dbb9a3991b8e7952a9c6e62f38"}, - {file = "orjson-3.10.4-cp311-none-win32.whl", hash = "sha256:f965893244fe348b59e5ce560693e6dd03368d577ce26849b5d261ce31c70101"}, - {file = "orjson-3.10.4-cp311-none-win_amd64.whl", hash = "sha256:c212f06fad6aa6ce85d5665e91a83b866579f29441a47d3865c57329c0857357"}, - {file = "orjson-3.10.4-cp312-cp312-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:d0965a8b0131959833ca8a65af60285995d57ced0de2fd8f16fc03235975d238"}, - {file = "orjson-3.10.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27b64695d9f2aef3ae15a0522e370ec95c946aaea7f2c97a1582a62b3bdd9169"}, - {file = "orjson-3.10.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:867d882ddee6a20be4c8b03ae3d2b0333894d53ad632d32bd9b8123649577171"}, - {file = "orjson-3.10.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a0667458f8a8ceb6dee5c08fec0b46195f92c474cbbec71dca2a6b7fd5b67b8d"}, - {file = "orjson-3.10.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3eac9befc4eaec1d1ff3bba6210576be4945332dde194525601c5ddb5c060d3"}, - {file = "orjson-3.10.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4343245443552eae240a33047a6d1bcac7a754ad4b1c57318173c54d7efb9aea"}, - {file = "orjson-3.10.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:30153e269eea43e98918d4d462a36a7065031d9246407dfff2579a4e457515c1"}, - {file = "orjson-3.10.4-cp312-none-win32.whl", hash = "sha256:1a7d092ee043abf3db19c2183115e80676495c9911843fdb3ebd48ca7b73079e"}, - {file = "orjson-3.10.4-cp312-none-win_amd64.whl", hash = "sha256:07a2adbeb8b9efe6d68fc557685954a1f19d9e33f5cc018ae1a89e96647c1b65"}, - {file = "orjson-3.10.4-cp38-cp38-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:f5a746f3d908bce1a1e347b9ca89864047533bdfab5a450066a0315f6566527b"}, - {file = "orjson-3.10.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:465b4a8a3e459f8d304c19071b4badaa9b267c59207a005a7dd9dfe13d3a423f"}, - {file = "orjson-3.10.4-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:35858d260728c434a3d91b60685ab32418318567e8902039837e1c2af2719e0b"}, - {file = "orjson-3.10.4-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8a5ba090d40c4460312dd69c232b38c2ff67a823185cfe667e841c9dd5c06841"}, - {file = "orjson-3.10.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5dde86755d064664e62e3612a166c28298aa8dfd35a991553faa58855ae739cc"}, - {file = "orjson-3.10.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:020a9e9001cfec85c156ef3b185ff758b62ef986cefdb8384c4579facd5ce126"}, - {file = "orjson-3.10.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:3bf8e6e3388a2e83a86466c912387e0f0a765494c65caa7e865f99969b76ba0d"}, - {file = "orjson-3.10.4-cp38-none-win32.whl", hash = "sha256:c5a1cca6a4a3129db3da68a25dc0a459a62ae58e284e363b35ab304202d9ba9e"}, - {file = "orjson-3.10.4-cp38-none-win_amd64.whl", hash = "sha256:ecd97d98d7bee3e3d51d0b51c92c457f05db4993329eea7c69764f9820e27eb3"}, - {file = "orjson-3.10.4-cp39-cp39-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:71362daa330a2fc85553a1469185ac448547392a8f83d34e67779f8df3a52743"}, - {file = "orjson-3.10.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d24b59d1fecb0fd080c177306118a143f7322335309640c55ed9580d2044e363"}, - {file = "orjson-3.10.4-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e906670aea5a605b083ebb58d575c35e88cf880fa372f7cedaac3d51e98ff164"}, - {file = "orjson-3.10.4-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7ce32ed4bc4d632268e4978e595fe5ea07e026b751482b4a0feec48f66a90abc"}, - {file = "orjson-3.10.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1dcd34286246e0c5edd0e230d1da2daab2c1b465fcb6bac85b8d44057229d40a"}, - {file = "orjson-3.10.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:c45d4b8c403e50beedb1d006a8916d9910ed56bceaf2035dc253618b44d0a161"}, - {file = "orjson-3.10.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:aaed3253041b5002a4f5bfdf6f7b5cce657d974472b0699a469d439beba40381"}, - {file = "orjson-3.10.4-cp39-none-win32.whl", hash = "sha256:9a4f41b7dbf7896f8dbf559b9b43dcd99e31e0d49ac1b59d74f52ce51ab10eb9"}, - {file = "orjson-3.10.4-cp39-none-win_amd64.whl", hash = "sha256:6c4eb7d867ed91cb61e6514cb4f457aa01d7b0fd663089df60a69f3d38b69d4c"}, - {file = "orjson-3.10.4.tar.gz", hash = "sha256:c912ed25b787c73fe994a5decd81c3f3b256599b8a87d410d799d5d52013af2a"}, + {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]] @@ -2361,13 +2366,13 @@ files = [ [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] @@ -2535,13 +2540,13 @@ files = [ [[package]] name = "pydantic" -version = "2.7.3" +version = "2.7.4" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.3-py3-none-any.whl", hash = "sha256:ea91b002777bf643bb20dd717c028ec43216b24a6001a280f83877fd2655d0b4"}, - {file = "pydantic-2.7.3.tar.gz", hash = "sha256:c46c76a40bb1296728d7a8b99aa73dd70a48c3510111ff290034f860c99c419e"}, + {file = "pydantic-2.7.4-py3-none-any.whl", hash = "sha256:ee8538d41ccb9c0a9ad3e0e5f07bf15ed8015b481ced539a1759d8cc89ae90d0"}, + {file = "pydantic-2.7.4.tar.gz", hash = "sha256:0c84efd9548d545f63ac0060c1e4d39bb9b14db8b3c0652338aecc07b5adec52"}, ] [package.dependencies] @@ -3524,13 +3529,13 @@ pytest = ">=7.0.0,<9.0.0" [[package]] name = "tenacity" -version = "8.3.0" +version = "8.4.1" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.3.0-py3-none-any.whl", hash = "sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185"}, - {file = "tenacity-8.3.0.tar.gz", hash = "sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2"}, + {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, + {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, ] [package.extras] @@ -3878,13 +3883,13 @@ dev = ["flake8", "flake8-annotations", "flake8-bandit", "flake8-bugbear", "flake [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.2" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.2.1-py3-none-any.whl", hash = "sha256:450b20ec296a467077128bff42b73080516e71b56ff59a60a02bef2232c4fa9d"}, - {file = "urllib3-2.2.1.tar.gz", hash = "sha256:d0570876c61ab9e520d776c38acbbb5b05a776d3f9ff98a5c8fd5162a444cf19"}, + {file = "urllib3-2.2.2-py3-none-any.whl", hash = "sha256:a448b2f64d686155468037e1ace9f2d2199776e17f0a46610480d311f73e3472"}, + {file = "urllib3-2.2.2.tar.gz", hash = "sha256:dd505485549a7a552833da5e6063639d0d177c04f23bc3864e41e5dc5f612168"}, ] [package.extras] From 47f777c0f26cf34ad3395125b7fd9903d8ece6f8 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 12:03:21 -0400 Subject: [PATCH 19/27] remove dockerfile, update readmes --- Dockerfile | 12 ----------- libs/sdk-js/README.md | 48 +++++++++++++++++++++++++++++++++++++++++++ libs/sdk-py/README.md | 36 +++++++++++++++++++++++++++++++- 3 files changed, 83 insertions(+), 13 deletions(-) delete mode 100644 Dockerfile create mode 100644 libs/sdk-js/README.md diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index c8ccdc80d..000000000 --- a/Dockerfile +++ /dev/null @@ -1,12 +0,0 @@ -FROM python:3.9 - -# Set the working directory to /app -WORKDIR /app - -# Copy the current directory contents into the container at /app -COPY . . - -# Install any needed packages specified in requirements.txt -RUN pip install poetry && poetry config virtualenvs.create false && poetry install --with test - -RUN poetry run pytest diff --git a/libs/sdk-js/README.md b/libs/sdk-js/README.md new file mode 100644 index 000000000..bf93d16f9 --- /dev/null +++ b/libs/sdk-js/README.md @@ -0,0 +1,48 @@ +# LangGraph JS/TS SDK + +This repository contains the JS/TS SDK for interacting with the LangGraph REST API. + +## Quick Start + +To get started with the JS/TS SDK, [install the package](https://www.npmjs.com/package/@langchain/langgraph-sdk) + +```bash +yarn add @langchain/langgraph-sdk +``` + +You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, SDK will automatically point at `http://localhost:8123`, otherwise +you would need to specify the server URL when creating a client. + +```js +import { Client } from "@langchain/langgraph-sdk"; + +const client = new Client(); + +// List all assistants +const assistants = await client.assistants.search({ + metadata: null, + offset: 0, + limit: 10, +}); + +// We auto-create an assistant for each graph you register in config. +const agent = assistants[0]; + +// Start a new thread +const thread = await client.threads.create(); + +// Start a streaming run +const messages = [{ role: "human", content: "whats the weather in la" }]; + +const streamResponse = client.runs.stream( + thread["thread_id"], + agent["assistant_id"], + { + input: { messages }, + } +); + +for await (const chunk of streamResponse) { + console.log(chunk); +} +``` \ No newline at end of file diff --git a/libs/sdk-py/README.md b/libs/sdk-py/README.md index 66351bf01..597644fd7 100644 --- a/libs/sdk-py/README.md +++ b/libs/sdk-py/README.md @@ -1 +1,35 @@ -# langgraph +# LangGraph Python SDK + +This repository contains the Python SDK for interacting with the LangGraph REST API. + +## Quick Start + +To get started with the Python SDK, [install the package](https://pypi.org/project/langgraph-sdk/) + +```bash +pip install -U langgraph-sdk +``` + +You will need a running LangGraph API server. If you're running a server locally using `langgraph-cli`, SDK will automatically point at `http://localhost:8123`, otherwise +you would need to specify the server URL when creating a client. + +```python +from langgraph_sdk import get_client + +# If you're using a remote server, initialize the client with `get_client(url=REMOTE_URL)` +client = get_client() + +# List all assistants +assistants = await client.assistants.search() + +# We auto-create an assistant for each graph you register in config. +agent = assistants[0] + +# Start a new thread +thread = await client.threads.create() + +# Start a streaming run +input = {"messages": [{"role": "human", "content": "whats the weather in la"}]} +async for chunk in client.runs.stream(thread['thread_id'], agent['assistant_id'], input=input): + print(chunk) +``` \ No newline at end of file From 2607d550fc61ef1ec058ad5d8a07f14ff04edba0 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 12:13:20 -0400 Subject: [PATCH 20/27] remove old docs reqs --- docs/docs-requirements.txt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 docs/docs-requirements.txt diff --git a/docs/docs-requirements.txt b/docs/docs-requirements.txt deleted file mode 100644 index 1fdbcfe5a..000000000 --- a/docs/docs-requirements.txt +++ /dev/null @@ -1,9 +0,0 @@ -mkdocs -mkdocstrings -mkdocstrings-python -mkdocs-jupyter -mkdocs-redirects -mkdocs-minify-plugin -mkdocs-rss-plugin -mkdocs-git-committers-plugin-2 -mkdocs-material[imaging] \ No newline at end of file From 5b72a3f2105f0ec6b284d4258e2e9a63de70c516 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 12:14:29 -0400 Subject: [PATCH 21/27] update authors --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 548e64293..5d76ae6be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -2,7 +2,7 @@ name = "langgraph-monorepo" version = "0.0.1" description = "LangGraph monorepo" -authors = ["Your Name "] +authors = [] license = "MIT" readme = "README.md" From 52395d2e1a8f7ff82ff627121272fcb280773521 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 12:16:01 -0400 Subject: [PATCH 22/27] spellcheck --- libs/sdk-js/README.md | 2 +- libs/sdk-py/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libs/sdk-js/README.md b/libs/sdk-js/README.md index bf93d16f9..b39b38983 100644 --- a/libs/sdk-js/README.md +++ b/libs/sdk-js/README.md @@ -32,7 +32,7 @@ const agent = assistants[0]; const thread = await client.threads.create(); // Start a streaming run -const messages = [{ role: "human", content: "whats the weather in la" }]; +const messages = [{ role: "human", content: "what's the weather in la" }]; const streamResponse = client.runs.stream( thread["thread_id"], diff --git a/libs/sdk-py/README.md b/libs/sdk-py/README.md index 597644fd7..74f121f68 100644 --- a/libs/sdk-py/README.md +++ b/libs/sdk-py/README.md @@ -29,7 +29,7 @@ agent = assistants[0] thread = await client.threads.create() # Start a streaming run -input = {"messages": [{"role": "human", "content": "whats the weather in la"}]} +input = {"messages": [{"role": "human", "content": "what's the weather in la"}]} async for chunk in client.runs.stream(thread['thread_id'], agent['assistant_id'], input=input): print(chunk) ``` \ No newline at end of file From 7e936c307857452a25e408aa7a70d180bf737307 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 13:13:57 -0400 Subject: [PATCH 23/27] remove js build files --- libs/sdk-js/client.cjs | 1 - libs/sdk-js/client.d.cts | 1 - libs/sdk-js/client.d.ts | 1 - libs/sdk-js/client.js | 1 - libs/sdk-js/index.cjs | 1 - libs/sdk-js/index.d.cts | 1 - libs/sdk-js/index.d.ts | 1 - libs/sdk-js/index.js | 1 - 8 files changed, 8 deletions(-) delete mode 100644 libs/sdk-js/client.cjs delete mode 100644 libs/sdk-js/client.d.cts delete mode 100644 libs/sdk-js/client.d.ts delete mode 100644 libs/sdk-js/client.js delete mode 100644 libs/sdk-js/index.cjs delete mode 100644 libs/sdk-js/index.d.cts delete mode 100644 libs/sdk-js/index.d.ts delete mode 100644 libs/sdk-js/index.js diff --git a/libs/sdk-js/client.cjs b/libs/sdk-js/client.cjs deleted file mode 100644 index 680e5bd38..000000000 --- a/libs/sdk-js/client.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist/client.cjs'); \ No newline at end of file diff --git a/libs/sdk-js/client.d.cts b/libs/sdk-js/client.d.cts deleted file mode 100644 index c90177f3b..000000000 --- a/libs/sdk-js/client.d.cts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/client.cjs' \ No newline at end of file diff --git a/libs/sdk-js/client.d.ts b/libs/sdk-js/client.d.ts deleted file mode 100644 index ca6f7c421..000000000 --- a/libs/sdk-js/client.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/client.mjs' \ No newline at end of file diff --git a/libs/sdk-js/client.js b/libs/sdk-js/client.js deleted file mode 100644 index ca6f7c421..000000000 --- a/libs/sdk-js/client.js +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/client.mjs' \ No newline at end of file diff --git a/libs/sdk-js/index.cjs b/libs/sdk-js/index.cjs deleted file mode 100644 index c84256f7a..000000000 --- a/libs/sdk-js/index.cjs +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('./dist/index.cjs'); \ No newline at end of file diff --git a/libs/sdk-js/index.d.cts b/libs/sdk-js/index.d.cts deleted file mode 100644 index 4adf1c804..000000000 --- a/libs/sdk-js/index.d.cts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/index.cjs' \ No newline at end of file diff --git a/libs/sdk-js/index.d.ts b/libs/sdk-js/index.d.ts deleted file mode 100644 index 307cab014..000000000 --- a/libs/sdk-js/index.d.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/index.mjs' \ No newline at end of file diff --git a/libs/sdk-js/index.js b/libs/sdk-js/index.js deleted file mode 100644 index 307cab014..000000000 --- a/libs/sdk-js/index.js +++ /dev/null @@ -1 +0,0 @@ -export * from './dist/index.mjs' \ No newline at end of file From e791f7ef5ae603fd7b95d7ab7a96b19f2d653d37 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 20:19:55 -0400 Subject: [PATCH 24/27] sync changes --- libs/cli/langgraph_cli/cli.py | 134 ++++++++++++++++++----- libs/cli/langgraph_cli/docker.py | 14 ++- libs/cli/langgraph_cli/util.py | 2 + libs/cli/pyproject.toml | 2 +- libs/cli/tests/unit_tests/test_cli.py | 4 +- libs/cli/tests/unit_tests/test_config.py | 3 +- libs/cli/tests/unit_tests/test_docker.py | 12 +- libs/sdk-js/package.json | 2 +- libs/sdk-js/src/client.mts | 2 +- libs/sdk-py/langgraph_sdk/client.py | 69 ++++++++++++ 10 files changed, 200 insertions(+), 44 deletions(-) create mode 100644 libs/cli/langgraph_cli/util.py diff --git a/libs/cli/langgraph_cli/cli.py b/libs/cli/langgraph_cli/cli.py index 69d66c75d..94b1d8a6a 100644 --- a/libs/cli/langgraph_cli/cli.py +++ b/libs/cli/langgraph_cli/cli.py @@ -13,8 +13,9 @@ from langgraph_cli.config import Config from langgraph_cli.docker import DockerCapabilities from langgraph_cli.exec import Runner, subp_exec from langgraph_cli.progress import Progress +from langgraph_cli.util import clean_empty_lines -OPT_O = click.option( +OPT_DOCKER_COMPOSE = click.option( "--docker-compose", "-d", help="Advanced: Path to docker-compose.yml file with additional services to launch", @@ -26,7 +27,7 @@ OPT_O = click.option( path_type=pathlib.Path, ), ) -OPT_C = click.option( +OPT_CONFIG = click.option( "--config", "-c", help="""Path to configuration file declaring dependencies, graphs and environment variables. @@ -127,11 +128,21 @@ OPT_VERBOSE = click.option( default=False, help="Show more output from the server logs", ) +OPT_WATCH = click.option("--watch", is_flag=True, help="Restart on file changes") +OPT_LANGGRAPH_API_PATH = click.option( + "--langgraph-api-path", + type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), + hidden=True, +) OPT_DEBUGGER_PORT = click.option( "--debugger-port", type=int, help="Pull the debugger image locally and serve the UI on specified port", ) +OPT_POSTGRES_URI = click.option( + "--postgres-uri", + help="Postgres URI to use for the database. Defaults to launching a local database", +) @click.group() @@ -142,16 +153,13 @@ def cli(): @OPT_RECREATE @OPT_PULL @OPT_PORT -@OPT_O -@OPT_C +@OPT_DOCKER_COMPOSE +@OPT_CONFIG @OPT_VERBOSE @OPT_DEBUGGER_PORT -@click.option("--watch", is_flag=True, help="Restart on file changes") -@click.option( - "--langgraph-api-path", - type=click.Path(exists=True, file_okay=False, dir_okay=True, resolve_path=True), - hidden=True, -) +@OPT_WATCH +@OPT_LANGGRAPH_API_PATH +@OPT_POSTGRES_URI @click.option( "--wait", is_flag=True, @@ -169,6 +177,7 @@ def up( wait: bool, verbose: bool, debugger_port: Optional[int], + postgres_uri: Optional[str], ): with Runner() as runner, Progress(message="Pulling...") as set: capabilities = langgraph_cli.docker.check_capabilities(runner) @@ -183,6 +192,7 @@ def up( langgraph_api_path=langgraph_api_path, verbose=verbose, debugger_port=debugger_port, + postgres_uri=postgres_uri, ) # add up + options args.extend(["up", "--remove-orphans"]) @@ -207,7 +217,7 @@ def up( debugger_origin = ( f"http://localhost:{debugger_port}" if debugger_port - else "https://dev.smith.langchain.com" + else "https://smith.langchain.com" ) set("") sys.stdout.write( @@ -237,8 +247,8 @@ def up( @OPT_PORT -@OPT_O -@OPT_C +@OPT_DOCKER_COMPOSE +@OPT_CONFIG @OPT_VERBOSE @OPT_DEBUGGER_PORT @cli.command(help="Stop langgraph API server") @@ -274,8 +284,8 @@ def down( runner.run(subp_exec(*compose_cmd, *args, input=stdin, verbose=verbose)) -@OPT_O -@OPT_C +@OPT_DOCKER_COMPOSE +@OPT_CONFIG @click.option("--follow", "-f", is_flag=True, help="Follow logs") @cli.command(help="Show langgraph API server logs") def logs( @@ -309,7 +319,7 @@ def logs( runner.run(subp_exec(*compose_cmd, *args, input=stdin, verbose=True)) -@OPT_C +@OPT_CONFIG @OPT_PULL @click.option( "--tag", @@ -374,33 +384,101 @@ def build( ) +@cli.group(help="Export langgraph compose files") +def export(): + pass + + +@click.option( + "--output", + "-o", + help="Output path to write the docker compose file to", + type=click.Path( + exists=False, + file_okay=True, + dir_okay=False, + resolve_path=True, + path_type=pathlib.Path, + ), + required=True, +) +@OPT_CONFIG @OPT_PORT -@OPT_O -@OPT_C -@cli.command(help="Build a helm chart to deploy to a Kubernetes cluster", hidden=True) -def helm( +@OPT_WATCH +@OPT_LANGGRAPH_API_PATH +@export.command(name="compose", help="Export docker compose file") +def export_compose( + output: pathlib.Path, + config: pathlib.Path, + port: int, + watch: bool, + langgraph_api_path: Optional[pathlib.Path], +): + with Runner() as runner: + capabilities = langgraph_cli.docker.check_capabilities(runner) + _, stdin = prepare( + runner, + capabilities=capabilities, + config_path=config, + docker_compose=None, + pull=False, + watch=watch, + langgraph_api_path=langgraph_api_path, + port=port, + verbose=False, + ) + + with open(output, "w") as f: + f.write(clean_empty_lines(stdin)) + + +@click.option( + "--output", + "-o", + help="Output path (directory) to write the helm chart to", + type=click.Path( + exists=False, + file_okay=False, + dir_okay=True, + resolve_path=True, + path_type=pathlib.Path, + ), + required=True, +) +@OPT_PORT +@OPT_DOCKER_COMPOSE +@OPT_CONFIG +@export.command( + name="helm", + help="Build and export a helm chart to deploy to a Kubernetes cluster", + hidden=True, +) +def export_helm( + output: pathlib.Path, config: pathlib.Path, docker_compose: Optional[pathlib.Path], port: int, ): with open(config) as f: config_json = langgraph_cli.config.validate_config(json.load(f)) + with Runner() as runner: # check docker available capabilities = langgraph_cli.docker.check_capabilities(runner) # prepare args stdin = langgraph_cli.docker.compose(capabilities, port=port) args = [ + "convert", "--chart", - "-o=./helm", + "-o", + str(output), "-v", - "-f", - "-", # stdin ] # apply options if docker_compose: args.extend(["-f", str(docker_compose)]) - args.append("convert") + + args.extend(["-f", "-"]) # stdin # apply config stdin += langgraph_cli.config.config_to_compose(config, config_json) # run kompose convert @@ -417,10 +495,14 @@ def prepare_args_and_stdin( watch: bool, langgraph_api_path: Optional[pathlib.Path], debugger_port: Optional[int] = None, + postgres_uri: Optional[str] = None, ): # prepare args stdin = langgraph_cli.docker.compose( - capabilities, port=port, debugger_port=debugger_port + capabilities, + port=port, + debugger_port=debugger_port, + postgres_uri=postgres_uri, ) args = [ "--project-directory", @@ -449,6 +531,7 @@ def prepare( langgraph_api_path: Optional[pathlib.Path], verbose: bool, debugger_port: Optional[int] = None, + postgres_uri: Optional[str] = None, ): with open(config_path) as f: config = langgraph_cli.config.validate_config(json.load(f)) @@ -472,5 +555,6 @@ def prepare( watch=watch, langgraph_api_path=langgraph_api_path, debugger_port=debugger_port, + postgres_uri=postgres_uri, ) return args, stdin diff --git a/libs/cli/langgraph_cli/docker.py b/libs/cli/langgraph_cli/docker.py index 5266ef316..d7627015f 100644 --- a/libs/cli/langgraph_cli/docker.py +++ b/libs/cli/langgraph_cli/docker.py @@ -77,12 +77,18 @@ def _parse_version(version: str) -> Version: def check_capabilities(runner) -> DockerCapabilities: # check docker available + if shutil.which("docker") is None: + raise click.UsageError("Docker not installed") from None + try: stdout, _ = runner.run(subp_exec("docker", "info", "-f", "json", collect=True)) info = json.loads(stdout) except (click.exceptions.Exit, json.JSONDecodeError): raise click.UsageError("Docker not installed or not running") from None + if not info["ServerVersion"]: + raise click.UsageError("Docker not running") from None + compose_type: DockerComposeType try: compose = next( @@ -146,15 +152,19 @@ def compose( langgraph-api: restart: on-failure ports: - - "{port}:8000" + - "{port}:8000\"""" + if include_db: + compose_str += """ depends_on: langgraph-postgres: - condition: service_healthy + condition: service_healthy""" + compose_str += f""" environment: POSTGRES_URI: {postgres_uri} """ if capabilities.healthcheck_start_interval: compose_str += """ healthcheck: + test: python /api/healthcheck.py interval: 60s start_interval: 1s start_period: 10s""" diff --git a/libs/cli/langgraph_cli/util.py b/libs/cli/langgraph_cli/util.py new file mode 100644 index 000000000..79b67a2c9 --- /dev/null +++ b/libs/cli/langgraph_cli/util.py @@ -0,0 +1,2 @@ +def clean_empty_lines(input_str: str): + return "\n".join(filter(None, input_str.splitlines())) diff --git a/libs/cli/pyproject.toml b/libs/cli/pyproject.toml index dca1782cb..0c67c03ee 100644 --- a/libs/cli/pyproject.toml +++ b/libs/cli/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "langgraph-cli" -version = "0.1.35" +version = "0.1.37" description = "CLI for interacting with LangGraph API" authors = ["Nuno Campos "] readme = "README.md" diff --git a/libs/cli/tests/unit_tests/test_cli.py b/libs/cli/tests/unit_tests/test_cli.py index 44f63bb2a..4d605443e 100644 --- a/libs/cli/tests/unit_tests/test_cli.py +++ b/libs/cli/tests/unit_tests/test_cli.py @@ -3,8 +3,7 @@ import pathlib from langgraph_cli.cli import prepare_args_and_stdin from langgraph_cli.config import Config, validate_config from langgraph_cli.docker import DEFAULT_POSTGRES_URI, DockerCapabilities, Version - -from .helpers import clean_empty_lines +from langgraph_cli.util import clean_empty_lines DEFAULT_DOCKER_CAPABILITIES = DockerCapabilities( version_docker=Version(26, 1, 1), @@ -81,6 +80,7 @@ services: environment: POSTGRES_URI: {DEFAULT_POSTGRES_URI} healthcheck: + test: python /api/healthcheck.py interval: 60s start_interval: 1s start_period: 10s diff --git a/libs/cli/tests/unit_tests/test_config.py b/libs/cli/tests/unit_tests/test_config.py index 9adcbd071..9d61a29c7 100644 --- a/libs/cli/tests/unit_tests/test_config.py +++ b/libs/cli/tests/unit_tests/test_config.py @@ -5,8 +5,7 @@ import click import pytest from langgraph_cli.config import config_to_compose, config_to_docker, validate_config - -from .helpers import clean_empty_lines +from langgraph_cli.util import clean_empty_lines PATH_TO_CONFIG = pathlib.Path("tests/unit_tests/test_config.json") diff --git a/libs/cli/tests/unit_tests/test_docker.py b/libs/cli/tests/unit_tests/test_docker.py index 425d97123..416c22889 100644 --- a/libs/cli/tests/unit_tests/test_docker.py +++ b/libs/cli/tests/unit_tests/test_docker.py @@ -4,7 +4,7 @@ from langgraph_cli.docker import ( Version, compose, ) -from tests.unit_tests.helpers import clean_empty_lines +from langgraph_cli.util import clean_empty_lines DEFAULT_DOCKER_CAPABILITIES = DockerCapabilities( version_docker=Version(26, 1, 1), @@ -24,9 +24,6 @@ def test_compose_with_no_debugger_and_custom_db(): restart: on-failure ports: - "{port}:8000" - depends_on: - langgraph-postgres: - condition: service_healthy environment: POSTGRES_URI: {custom_postgres_uri}""" assert clean_empty_lines(actual_compose_str) == expected_compose_str @@ -45,12 +42,10 @@ def test_compose_with_no_debugger_and_custom_db_with_healthcheck(): restart: on-failure ports: - "{port}:8000" - depends_on: - langgraph-postgres: - condition: service_healthy environment: POSTGRES_URI: {custom_postgres_uri} healthcheck: + test: python /api/healthcheck.py interval: 60s start_interval: 1s start_period: 10s""" @@ -70,9 +65,6 @@ def test_compose_with_debugger_and_custom_db(): restart: on-failure ports: - "{port}:8000" - depends_on: - langgraph-postgres: - condition: service_healthy environment: POSTGRES_URI: {custom_postgres_uri}""" assert clean_empty_lines(actual_compose_str) == expected_compose_str diff --git a/libs/sdk-js/package.json b/libs/sdk-js/package.json index fd7ee23e3..6edf725d1 100644 --- a/libs/sdk-js/package.json +++ b/libs/sdk-js/package.json @@ -1,6 +1,6 @@ { "name": "@langchain/langgraph-sdk", - "version": "0.0.1-rc.11", + "version": "0.0.1-rc.12", "description": "Client library for interacting with the LangGraph API", "type": "module", "packageManager": "yarn@1.22.19", diff --git a/libs/sdk-js/src/client.mts b/libs/sdk-js/src/client.mts index 6e49af778..7d2fd1472 100644 --- a/libs/sdk-js/src/client.mts +++ b/libs/sdk-js/src/client.mts @@ -97,7 +97,7 @@ class BaseClient { const response = await this.asyncCaller.fetch( ...this.prepareFetchOptions(path, options), ); - if (response.status == 202) { + if (response.status === 202 || response.status === 204) { return undefined as T; } return response.json() as T; diff --git a/libs/sdk-py/langgraph_sdk/client.py b/libs/sdk-py/langgraph_sdk/client.py index 8c753f3ab..bfdf9a28a 100644 --- a/libs/sdk-py/langgraph_sdk/client.py +++ b/libs/sdk-py/langgraph_sdk/client.py @@ -67,6 +67,7 @@ class LangGraphClient: self.assistants = AssistantsClient(self.http) self.threads = ThreadsClient(self.http) self.runs = RunsClient(self.http) + self.crons = CronClient(self.http) class HttpClient: @@ -620,6 +621,74 @@ class RunsClient: await self.http.delete(f"/threads/{thread_id}/runs/{run_id}") +class CronClient: + def __init__(self, http_client: HttpClient) -> None: + self.http = http_client + + async def create_for_thread( + self, + thread_id: str, + assistant_id: str, + *, + schedule: str, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + webhook: Optional[str] = None, + multitask_strategy: Optional[str] = None, + ) -> Run: + """Create a background run.""" + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.post(f"/threads/{thread_id}/runs/crons", json=payload) + + async def create( + self, + assistant_id: str, + *, + schedule: str, + input: Optional[dict] = None, + metadata: Optional[dict] = None, + config: Optional[Config] = None, + interrupt_before: Optional[list[str]] = None, + interrupt_after: Optional[list[str]] = None, + webhook: Optional[str] = None, + multitask_strategy: Optional[str] = None, + ) -> Run: + """Create a background run.""" + payload = { + "schedule": schedule, + "input": input, + "config": config, + "metadata": metadata, + "assistant_id": assistant_id, + "interrupt_before": interrupt_before, + "interrupt_after": interrupt_after, + "webhook": webhook, + } + if multitask_strategy: + payload["multitask_strategy"] = multitask_strategy + payload = {k: v for k, v in payload.items() if v is not None} + return await self.http.post("/runs/crons", json=payload) + + async def delete(self, cron_id: str) -> None: + """Delete a cron.""" + await self.http.delete(f"/runs/crons/{cron_id}") + + def _get_api_key(api_key: Optional[str] = None) -> Optional[str]: """Get the API key from the environment. Precedence: From 2c8806a974c53bf5a2952df883fc495859e7e9c0 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 20:24:04 -0400 Subject: [PATCH 25/27] pyproject warning --- pyproject.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/pyproject.toml b/pyproject.toml index 5d76ae6be..d14588c4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,6 +5,7 @@ description = "LangGraph monorepo" authors = [] license = "MIT" readme = "README.md" +package-mode = false [tool.poetry.dependencies] python = "^3.10" From 8be35f3b59a86cdf1033243b64ca8662a90a2e27 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 20:27:33 -0400 Subject: [PATCH 26/27] Revert "pyproject warning" This reverts commit 2c8806a974c53bf5a2952df883fc495859e7e9c0. --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d14588c4b..5d76ae6be 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -5,7 +5,6 @@ description = "LangGraph monorepo" authors = [] license = "MIT" readme = "README.md" -package-mode = false [tool.poetry.dependencies] python = "^3.10" From b35bb19b31625b819ff5455fedc31505f4b47bf5 Mon Sep 17 00:00:00 2001 From: vbarda Date: Tue, 18 Jun 2024 20:38:40 -0400 Subject: [PATCH 27/27] sync again --- libs/cli/langgraph_cli/cli.py | 2 ++ libs/cli/langgraph_cli/docker.py | 2 -- libs/cli/tests/unit_tests/test_cli.py | 2 -- libs/cli/tests/unit_tests/test_docker.py | 5 ----- 4 files changed, 2 insertions(+), 9 deletions(-) diff --git a/libs/cli/langgraph_cli/cli.py b/libs/cli/langgraph_cli/cli.py index 94b1d8a6a..cc4cd6b73 100644 --- a/libs/cli/langgraph_cli/cli.py +++ b/libs/cli/langgraph_cli/cli.py @@ -207,6 +207,8 @@ def up( args.append("--watch") if wait: args.append("--wait") + else: + args.append("--abort-on-container-exit") # run docker compose set("Building...") diff --git a/libs/cli/langgraph_cli/docker.py b/libs/cli/langgraph_cli/docker.py index d7627015f..658e1268e 100644 --- a/libs/cli/langgraph_cli/docker.py +++ b/libs/cli/langgraph_cli/docker.py @@ -16,7 +16,6 @@ DEFAULT_POSTGRES_URI = ( DB = """ langgraph-postgres: image: postgres:16 - restart: on-failure ports: - "5433:5432" environment: @@ -150,7 +149,6 @@ def compose( {db} {DEBUGGER.format(debugger_port=debugger_port) if debugger_port else ""} langgraph-api: - restart: on-failure ports: - "{port}:8000\"""" if include_db: diff --git a/libs/cli/tests/unit_tests/test_cli.py b/libs/cli/tests/unit_tests/test_cli.py index 4d605443e..d316228a9 100644 --- a/libs/cli/tests/unit_tests/test_cli.py +++ b/libs/cli/tests/unit_tests/test_cli.py @@ -46,7 +46,6 @@ def test_prepare_args_and_stdin(): services: langgraph-postgres: image: postgres:16 - restart: on-failure ports: - "5433:5432" environment: @@ -71,7 +70,6 @@ services: langgraph-postgres: condition: service_healthy langgraph-api: - restart: on-failure ports: - "8000:8000" depends_on: diff --git a/libs/cli/tests/unit_tests/test_docker.py b/libs/cli/tests/unit_tests/test_docker.py index 416c22889..4d5e09b94 100644 --- a/libs/cli/tests/unit_tests/test_docker.py +++ b/libs/cli/tests/unit_tests/test_docker.py @@ -21,7 +21,6 @@ def test_compose_with_no_debugger_and_custom_db(): ) expected_compose_str = f"""services: langgraph-api: - restart: on-failure ports: - "{port}:8000" environment: @@ -39,7 +38,6 @@ def test_compose_with_no_debugger_and_custom_db_with_healthcheck(): ) expected_compose_str = f"""services: langgraph-api: - restart: on-failure ports: - "{port}:8000" environment: @@ -62,7 +60,6 @@ def test_compose_with_debugger_and_custom_db(): ) expected_compose_str = f"""services: langgraph-api: - restart: on-failure ports: - "{port}:8000" environment: @@ -79,7 +76,6 @@ def test_compose_with_debugger_and_default_db(): services: langgraph-postgres: image: postgres:16 - restart: on-failure ports: - "5433:5432" environment: @@ -95,7 +91,6 @@ services: retries: 5 interval: 5s langgraph-api: - restart: on-failure ports: - "{port}:8000" depends_on: