From 4c12044501235c58b9e13662e8da5af1d61d2022 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 7 Jun 2024 10:29:17 +0300 Subject: [PATCH 01/41] feat: Version each of bot & df_designer dirs --- .github/workflows/e2e_test.yml | 1 + Dockerfile | 15 +++---- .../app/api/api_v1/endpoints/flows.py | 39 +++++++++++++--- backend/df_designer/app/cli.py | 21 ++++++++- backend/df_designer/app/core/config.py | 2 +- backend/df_designer/app/core/logger_config.py | 2 +- .../app/services/json_translator.py | 31 +++++++++++-- .../df_designer/app/tests/api/test_flows.py | 28 ++++++++++-- backend/df_designer/app/tests/e2e/test_e2e.py | 5 +++ .../tests/integration/test_api_integration.py | 4 +- backend/df_designer/app/utils/__init__.py | 0 backend/df_designer/app/utils/git_cmd.py | 18 ++++++++ backend/df_designer/poetry.lock | 45 ++++++++++++++++++- backend/df_designer/pyproject.toml | 1 + frontend/src/pages/NodesLayout.tsx | 9 ++-- 15 files changed, 189 insertions(+), 32 deletions(-) create mode 100644 backend/df_designer/app/utils/__init__.py create mode 100644 backend/df_designer/app/utils/git_cmd.py diff --git a/.github/workflows/e2e_test.yml b/.github/workflows/e2e_test.yml index 92321216..65a14d3c 100644 --- a/.github/workflows/e2e_test.yml +++ b/.github/workflows/e2e_test.yml @@ -4,6 +4,7 @@ # push: # branches: # - dev +# - master # pull_request: # branches: # - dev diff --git a/Dockerfile b/Dockerfile index 7ee29af6..e21f9846 100644 --- a/Dockerfile +++ b/Dockerfile @@ -21,7 +21,6 @@ FROM python:3.10-slim as backend-builder WORKDIR /temp ARG PROJECT_DIR -# ENV PROJECT_DIR ${PROJECT_DIR} ENV POETRY_VERSION=1.8.2 \ POETRY_HOME=/poetry \ @@ -37,8 +36,6 @@ ENV PATH="${PATH}:${POETRY_VENV}/bin" COPY ./backend/df_designer /temp/backend/df_designer COPY --from=frontend-builder /temp/frontend/dist /temp/backend/df_designer/app/static -COPY ./${PROJECT_DIR} /temp/${PROJECT_DIR} - # Build the wheel WORKDIR /temp/backend/df_designer RUN poetry build @@ -51,6 +48,12 @@ FROM python:3.10-slim as runtime ARG PROJECT_DIR +# Install Git +RUN apt-get update && apt-get install -y git + +# Set the GIT_PYTHON_GIT_EXECUTABLE environment variable +ENV GIT_PYTHON_GIT_EXECUTABLE=/usr/bin/git + COPY --from=backend-builder /poetry-venv /poetry-venv # Set environment variable to use the virtualenv @@ -62,10 +65,6 @@ COPY ./${PROJECT_DIR} /src2/project_dir # Install the wheel WORKDIR /src2/project_dir -RUN poetry lock --no-update \ - && poetry install +RUN poetry install CMD ["poetry", "run", "dflowd", "run_backend"] - - -# #TODO: change scr to app (maybe) \ No newline at end of file diff --git a/backend/df_designer/app/api/api_v1/endpoints/flows.py b/backend/df_designer/app/api/api_v1/endpoints/flows.py index ef7d8654..96eedff6 100644 --- a/backend/df_designer/app/api/api_v1/endpoints/flows.py +++ b/backend/df_designer/app/api/api_v1/endpoints/flows.py @@ -1,23 +1,52 @@ -from fastapi import APIRouter +from fastapi import APIRouter, HTTPException, status +from git import Repo from omegaconf import OmegaConf from app.core.config import settings from app.core.logger_config import get_logger from app.db.base import read_conf, write_conf +from app.utils.git_cmd import commit_changes, get_repo router = APIRouter() logger = get_logger(__name__) -@router.get("/") -async def flows_get(): +@router.get("/{build_id}") +async def flows_get(build_id: str): + repo = Repo.init(settings.frontend_flows_path.parent) + for tag in repo.tags: + if tag.name == str(build_id): + break + else: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Build_id {build_id} doesn't exist", + ) + + repo.git.checkout(build_id, settings.frontend_flows_path.name) + omega_flows = await read_conf(settings.frontend_flows_path) dict_flows = OmegaConf.to_container(omega_flows, resolve=True) return {"status": "ok", "data": dict_flows} -@router.post("/") -async def flows_post(flows: dict) -> dict[str, str]: +@router.post("/{build_id}") +async def flows_post(flows: dict, build_id: str) -> dict[str, str]: + repo = get_repo(settings.frontend_flows_path.parent) + for tag in repo.tags: + if tag.name == str(build_id): + raise HTTPException( + status_code=status.HTTP_409_CONFLICT, + detail=f"Build_id {build_id} already exists", + ) + await write_conf(flows, settings.frontend_flows_path) + logger.info("Flows saved to DB") + + commit_changes(repo, "Save frontend flows") + repo.create_tag(build_id) + + logger.info("Flows saved to git with tag %s", build_id) + return {"status": "ok"} diff --git a/backend/df_designer/app/cli.py b/backend/df_designer/app/cli.py index ef81411c..5ba56825 100644 --- a/backend/df_designer/app/cli.py +++ b/backend/df_designer/app/cli.py @@ -7,14 +7,23 @@ import typer import uvicorn from cookiecutter.main import cookiecutter +from git import Repo from app.core.config import settings from app.core.logger_config import get_logger from app.services.json_translator import translator +from app.utils.git_cmd import commit_changes cli = typer.Typer() +def init_new_repo(git_path: Path, tag_name: str): + repo = Repo.init(git_path) + repo.git.checkout(b="dev") + commit_changes(repo, "Init frontend flows") + repo.create_tag(tag_name) + + async def _execute_command(command_to_run): logger = get_logger(__name__) try: @@ -76,7 +85,11 @@ def run_bot(build_id: int, project_dir: str = settings.work_directory, preset: s @cli.command("run_scenario") def run_scenario(build_id: int, project_dir: str = ".", call_from_open_event_loop: bool = False): - script_path = Path(project_dir) / "bot" / "scripts" / f"build_{build_id}.yaml" + # checkout the commit and then run the build + bot_repo = Repo.init(Path(project_dir) / "bot") + bot_repo.git.checkout(build_id, "scripts/build.yaml") + + script_path = Path(project_dir) / "bot" / "scripts" / "build.yaml" if not script_path.exists(): raise FileNotFoundError(f"File {script_path} doesn't exist") command_to_run = f"poetry run python {project_dir}/app.py --script-path {script_path}" @@ -121,10 +134,14 @@ def init(destination: str = settings.work_directory, no_input: bool = False, ove original_dir = os.getcwd() try: os.chdir(destination) - cookiecutter( + proj_path = cookiecutter( "https://github.com/Ramimashkouk/df_d_template.git", no_input=no_input, overwrite_if_exists=overwrite_if_exists, + checkout="feat/versioning", ) finally: os.chdir(original_dir) + + init_new_repo(Path(proj_path) / "bot", tag_name="43") + init_new_repo(Path(proj_path) / "df_designer", tag_name="43") diff --git a/backend/df_designer/app/core/config.py b/backend/df_designer/app/core/config.py index dd2be431..13f3ba81 100644 --- a/backend/df_designer/app/core/config.py +++ b/backend/df_designer/app/core/config.py @@ -8,7 +8,7 @@ class Settings(BaseSettings): API_V1_STR: str = "/api/v1" APP: str = "app.main:app" - work_directory: str = "." + work_directory: Path = Path(".") config_file_path: Path = Path(__file__).absolute() static_files: Path = config_file_path.parent.with_name("static") start_page: Path = static_files.joinpath("index.html") diff --git a/backend/df_designer/app/core/logger_config.py b/backend/df_designer/app/core/logger_config.py index ae081e9a..7bd734e4 100644 --- a/backend/df_designer/app/core/logger_config.py +++ b/backend/df_designer/app/core/logger_config.py @@ -1,7 +1,7 @@ import logging from datetime import datetime from pathlib import Path -from typing import Optional, Literal +from typing import Literal, Optional from app.core.config import settings diff --git a/backend/df_designer/app/services/json_translator.py b/backend/df_designer/app/services/json_translator.py index 7e5b97ec..0a8c026e 100644 --- a/backend/df_designer/app/services/json_translator.py +++ b/backend/df_designer/app/services/json_translator.py @@ -1,17 +1,21 @@ from pathlib import Path from typing import Tuple +from git import Repo + from app.api.deps import get_index +from app.core.config import settings from app.core.logger_config import get_logger from app.db.base import read_conf, write_conf +from app.utils.git_cmd import commit_changes, get_repo logger = get_logger(__name__) -def get_db_paths(build_id: int, project_dir: Path, custom_dir: str) -> Tuple[Path, Path, Path]: +def get_db_paths(project_dir: Path, custom_dir: str) -> Tuple[Path, Path, Path]: frontend_graph_path = project_dir / "df_designer" / "frontend_flows.yaml" custom_conditions_file = project_dir / "bot" / custom_dir / "conditions.py" - script_path = project_dir / "bot" / "scripts" / f"build_{build_id}.yaml" + script_path = project_dir / "bot" / "scripts" / "build.yaml" if not frontend_graph_path.exists(): raise FileNotFoundError(f"File {frontend_graph_path} doesn't exist") @@ -133,12 +137,31 @@ async def replace_condition(condition, conditions_lines, cnd_strt_lineno, index) return all_lines +def save_version_to_git(build_id: int, bot_repo: Repo): + # Save current version of frontend script + df_designer_repo = get_repo(settings.frontend_flows_path.parent) + commit_changes(df_designer_repo, f"Save script: {build_id}") + df_designer_repo.create_tag(build_id) + logger.info("Flows saved to git with tag %s", build_id) + + # Save built version of dff bot + commit_changes(bot_repo, f"create build: {build_id}") + bot_repo.create_tag(build_id) + logger.info("Bot saved to git with tag %s", build_id) + + async def translator(build_id: int, project_dir: str, custom_dir: str = "custom"): + bot_repo = get_repo(Path(project_dir) / "bot") + # check that there's no already existing tag {build_id} + for tag in bot_repo.tags: + if tag.name == str(build_id): + raise ValueError(f"Tag {build_id} already exists") + index = get_index() await index.load() index.logger.debug("Loaded index '%s'", index.index) - frontend_graph_path, script_path, custom_conditions_file = get_db_paths(build_id, Path(project_dir), custom_dir) + frontend_graph_path, script_path, custom_conditions_file = get_db_paths(Path(project_dir), custom_dir) script = { "CONFIG": {"custom_dir": "/".join(["..", custom_dir])}, @@ -182,3 +205,5 @@ async def translator(build_id: int, project_dir: str, custom_dir: str = "custom" write_conditions_to_file(conditions_lines, custom_conditions_file) await write_conf(script, script_path) + + save_version_to_git(build_id, bot_repo) diff --git a/backend/df_designer/app/tests/api/test_flows.py b/backend/df_designer/app/tests/api/test_flows.py index ba4ada64..54867bd3 100644 --- a/backend/df_designer/app/tests/api/test_flows.py +++ b/backend/df_designer/app/tests/api/test_flows.py @@ -3,18 +3,38 @@ from omegaconf import OmegaConf from app.api.api_v1.endpoints.flows import flows_get, flows_post +from app.core.config import settings @pytest.mark.asyncio async def test_flows_get(mocker): - mocker.patch("app.api.api_v1.endpoints.flows.read_conf", return_value=OmegaConf.create({"foo": "bar"})) - response = await flows_get() + read_conf = mocker.patch("app.api.api_v1.endpoints.flows.read_conf", return_value=OmegaConf.create({"foo": "bar"})) + + bot_repo = mocker.MagicMock() + tag = mocker.MagicMock() + tag.name = "43" + bot_repo.tags = [tag] + mocker.patch("app.api.api_v1.endpoints.flows.Repo.init", return_value=bot_repo) + + response = await flows_get("43") + + read_conf.assert_called_with(settings.frontend_flows_path) + bot_repo.git.checkout.assert_called_once_with("43", settings.frontend_flows_path.name) assert response["status"] == "ok" assert response["data"] == {"foo": "bar"} @pytest.mark.asyncio async def test_flows_post(mocker): - mocker.patch("app.api.api_v1.endpoints.flows.write_conf", return_value={}) - response = await flows_post({"foo": "bar"}) + write_conf = mocker.patch("app.api.api_v1.endpoints.flows.write_conf") + get_repo = mocker.patch("app.api.api_v1.endpoints.flows.get_repo") + commit_changes = mocker.patch("app.api.api_v1.endpoints.flows.commit_changes") + + response = await flows_post({"foo": "bar"}, "save1") + + write_conf.assert_called_with({"foo": "bar"}, settings.frontend_flows_path) + get_repo.assert_called_with(settings.frontend_flows_path.parent) + repo = get_repo.return_value + commit_changes.assert_called_with(repo, "Save frontend flows") + repo.create_tag.assert_called_with("save1") assert response["status"] == "ok" diff --git a/backend/df_designer/app/tests/e2e/test_e2e.py b/backend/df_designer/app/tests/e2e/test_e2e.py index 88daf4ce..82c69863 100644 --- a/backend/df_designer/app/tests/e2e/test_e2e.py +++ b/backend/df_designer/app/tests/e2e/test_e2e.py @@ -6,10 +6,12 @@ from httpx_ws.transport import ASGIWebSocketTransport from app.api.deps import get_build_manager, get_run_manager +from app.core.config import settings from app.core.logger_config import get_logger from app.main import app from app.schemas.process_status import Status from app.tests.conftest import override_dependency, start_process +from app.utils.git_cmd import delete_tag, get_repo logger = get_logger(__name__) @@ -23,6 +25,7 @@ async def _assert_process_status(response, process_manager): async def test_all(mocker): async with httpx.AsyncClient(transport=ASGIWebSocketTransport(app)) as client: async with override_dependency(mocker, get_build_manager) as process_manager: + mocker.patch("app.services.process_manager.max", return_value=9999) response = await start_process( client, endpoint="http://localhost:8000/api/v1/bot/build/start", @@ -56,3 +59,5 @@ async def test_all(mocker): async with aconnect_ws(f"http://localhost:8000/api/v1/bot/run/connect?run_id={run_id}", client) as ws: message = await ws.receive_text() assert message == "Start chatting" + repo = get_repo(settings.work_directory / "bot") + delete_tag(repo, "10000") diff --git a/backend/df_designer/app/tests/integration/test_api_integration.py b/backend/df_designer/app/tests/integration/test_api_integration.py index 3ee9bbfe..5cc6ae5d 100644 --- a/backend/df_designer/app/tests/integration/test_api_integration.py +++ b/backend/df_designer/app/tests/integration/test_api_integration.py @@ -70,12 +70,12 @@ async def _test_stop_process(mocker, get_manager_func, start_endpoint, stop_endp # Test flows endpoints and interaction with db (read and write conf) def test_flows(client): # noqa: F811 - get_response = client.get("/api/v1/flows") + get_response = client.get("/api/v1/flows/43") assert get_response.status_code == 200 data = get_response.json()["data"] assert "flows" in data - response = client.post("/api/v1/flows", json=data) + response = client.post("/api/v1/flows/test_save1", json=data) assert response.status_code == 200 diff --git a/backend/df_designer/app/utils/__init__.py b/backend/df_designer/app/utils/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/df_designer/app/utils/git_cmd.py b/backend/df_designer/app/utils/git_cmd.py new file mode 100644 index 00000000..f203a561 --- /dev/null +++ b/backend/df_designer/app/utils/git_cmd.py @@ -0,0 +1,18 @@ +from pathlib import Path + +from git import Repo + + +def commit_changes(repo, commit_message): + repo.git.add(A=True) + repo.index.commit(commit_message) + + +def get_repo(project_dir: Path): + repo = Repo(project_dir) + assert not repo.bare + return repo + + +def delete_tag(repo: Repo, tag_name: str): + repo.git.tag("-d", tag_name) diff --git a/backend/df_designer/poetry.lock b/backend/df_designer/poetry.lock index 790cec79..f89a04f2 100644 --- a/backend/df_designer/poetry.lock +++ b/backend/df_designer/poetry.lock @@ -368,6 +368,38 @@ mccabe = ">=0.6.0,<0.7.0" pycodestyle = ">=2.8.0,<2.9.0" pyflakes = ">=2.4.0,<2.5.0" +[[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 = "h11" version = "0.14.0" @@ -1124,6 +1156,17 @@ files = [ {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 = "sniffio" version = "1.3.1" @@ -1568,4 +1611,4 @@ h11 = ">=0.9.0,<1" [metadata] lock-version = "2.0" python-versions = "^3.10" -content-hash = "cd2676c8cf6f5295bbdc51457c722ee03a05b85117b73e99b21de8bc465b040c" +content-hash = "ffb8f821b686b31e33b85141af24b10e893419ee40bc86c834596800351a810c" diff --git a/backend/df_designer/pyproject.toml b/backend/df_designer/pyproject.toml index b0c83662..55988888 100644 --- a/backend/df_designer/pyproject.toml +++ b/backend/df_designer/pyproject.toml @@ -27,6 +27,7 @@ pytest-asyncio = "^0.23.6" pytest-mock = "^3.14.0" httpx = "^0.27.0" httpx-ws = "^0.6.0" +gitpython = "^3.1.43" [tool.poetry.scripts] dflowd = "app.cli:cli" diff --git a/frontend/src/pages/NodesLayout.tsx b/frontend/src/pages/NodesLayout.tsx index f3d1ca65..0b3cda02 100644 --- a/frontend/src/pages/NodesLayout.tsx +++ b/frontend/src/pages/NodesLayout.tsx @@ -19,7 +19,6 @@ const NodesLayout = () => { node.type !== "link" && node.data.name !== "LOCAL NODE" && node.data.name !== "GLOBAL NODE" ) const edges = useEdges() - console.log(nodes, edges) const [hoveredNode, setHoveredNode] = useState("") const setHoveredNodeHandler: MouseEventHandler = (e) => { const id = (e.target as HTMLElement).id @@ -39,7 +38,7 @@ const NodesLayout = () => { key={node.id} className='flex flex-col gap-1'>
@@ -69,11 +68,11 @@ const NodesLayout = () => { return ( Date: Thu, 8 Aug 2024 10:58:55 +0300 Subject: [PATCH 02/41] style: Black up --- backend/df_designer/app/services/json_converter.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/backend/df_designer/app/services/json_converter.py b/backend/df_designer/app/services/json_converter.py index 7474ff4e..ac1b6bfa 100644 --- a/backend/df_designer/app/services/json_converter.py +++ b/backend/df_designer/app/services/json_converter.py @@ -250,8 +250,9 @@ async def converter(build_id: int, project_dir: str, custom_dir: str = "custom") await index.load() index.logger.debug("Loaded index '%s'", index.index) - frontend_graph_path, script_path, custom_conditions_file, custom_responses_file = _get_db_paths(Path(project_dir), custom_dir) - + frontend_graph_path, script_path, custom_conditions_file, custom_responses_file = _get_db_paths( + Path(project_dir), custom_dir + ) script = { "CONFIG": {"custom_dir": "/".join(["..", custom_dir])}, From 7ffb675c1eb54754d68533caad6231c174678f3c Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 4 Oct 2024 22:59:02 +0800 Subject: [PATCH 03/41] fix: Delete is_alive & slot interface --- backend/chatsky_ui/services/process.py | 13 +------------ .../ConditionModal/components/SlotCondition.tsx | 1 + 2 files changed, 2 insertions(+), 12 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 1a042203..96f0b32e 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -180,18 +180,7 @@ async def write_stdin(self, message: bytes) -> None: async def is_alive(self) -> bool: """Checks if the process is alive by writing to stdin andreading its stdout.""" - message = b"Hi\n" - try: - # Attempt to write and read from the process with a timeout. - await self.write_stdin(message) - output = await asyncio.wait_for(self.read_stdout(), timeout=PING_PONG_TIMEOUT) - if not output: - return False - self.logger.debug("Process is alive and output afer communication is: %s", output.decode()) - return True - except asyncio.exceptions.TimeoutError: - self.logger.debug("Process is still running.") - return False + return True class RunProcess(Process): diff --git a/frontend/src/modals/ConditionModal/components/SlotCondition.tsx b/frontend/src/modals/ConditionModal/components/SlotCondition.tsx index 61560ba2..21d32fc4 100644 --- a/frontend/src/modals/ConditionModal/components/SlotCondition.tsx +++ b/frontend/src/modals/ConditionModal/components/SlotCondition.tsx @@ -103,6 +103,7 @@ const SlotCondition = ({ condition, setData }: ConditionModalContentType) => { value: slot.name, }))} placeholder="Choose slot" + onValueChange={(value) => setSelectedSlot(value)} /> From 2c4a1058e921cfb292bb1791deb1950d2b74fd1a Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 8 Oct 2024 22:25:17 +0800 Subject: [PATCH 04/41] fix: Run python3 if python wasn't found --- backend/chatsky_ui/cli.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index a50e5376..6b5f526a 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -126,7 +126,11 @@ def run_scenario( script_path = settings.scripts_dir / f"build_{build_id}.yaml" command_to_run = f"python {project_dir}/app.py --script-path {script_path}" - asyncio.run(_execute_command(command_to_run)) + try: + asyncio.run(_execute_command(command_to_run)) + except FileNotFoundError: + command_to_run = f"python3 {project_dir}/app.py --script-path {script_path}" + asyncio.run(_execute_command(command_to_run)) @cli.command("run_app") From ca9c92f82792803b87dc8b9535ed12b0a06296cc Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 11 Oct 2024 12:27:56 +0800 Subject: [PATCH 05/41] refactor: Reorganize json_converter into classes --- backend/chatsky_ui/cli.py | 8 +- .../front_graph_components/base_component.py | 4 + .../schemas/front_graph_components/flow.py | 9 ++ .../info_holders/__init__.py | 0 .../info_holders/condition.py | 13 +++ .../info_holders/response.py | 13 +++ .../front_graph_components/interface.py | 21 +++++ .../schemas/front_graph_components/node.py | 22 +++++ .../front_graph_components/pipeline.py | 8 ++ .../schemas/front_graph_components/script.py | 7 ++ .../schemas/front_graph_components/slot.py | 16 ++++ .../json_converter_new2/base_converter.py | 9 ++ .../condition_finder.py | 0 .../services/json_converter_new2/consts.py | 3 + .../json_converter_new2/flow_converter.py | 68 ++++++++++++++ .../interface_converter.py | 9 ++ .../condition_converter.py | 59 ++++++++++++ .../response_converter.py | 46 +++++++++ .../json_converter_new2/node_converter.py | 94 +++++++++++++++++++ .../json_converter_new2/pipeline_converter.py | 46 +++++++++ .../json_converter_new2/script_converter.py | 34 +++++++ .../json_converter_new2/slots_converter.py | 79 ++++++++++++++++ 22 files changed, 566 insertions(+), 2 deletions(-) create mode 100644 backend/chatsky_ui/schemas/front_graph_components/base_component.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/flow.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/info_holders/__init__.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/info_holders/response.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/interface.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/node.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/pipeline.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/script.py create mode 100644 backend/chatsky_ui/schemas/front_graph_components/slot.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/base_converter.py rename backend/chatsky_ui/services/{ => json_converter_new2}/condition_finder.py (100%) create mode 100644 backend/chatsky_ui/services/json_converter_new2/consts.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/flow_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/interface_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/node_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/script_converter.py create mode 100644 backend/chatsky_ui/services/json_converter_new2/slots_converter.py diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index a50e5376..783cd093 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -9,6 +9,7 @@ import typer from cookiecutter.main import cookiecutter from typing_extensions import Annotated +import yaml # Patch nest_asyncio before importing Chatsky nest_asyncio.apply = lambda: None @@ -93,9 +94,12 @@ def build_scenario( raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - from chatsky_ui.services.json_converter import converter # pylint: disable=C0415 + from chatsky_ui.services.json_converter_new2.pipeline_converter import PipelineConverter # pylint: disable=C0415 - asyncio.run(converter(build_id=build_id)) + pipeline_converter = PipelineConverter(pipeline_id=build_id) + pipeline_converter( + input_file=settings.frontend_flows_path, output_dir=settings.scripts_dir + ) #TODO: rename to frontend_graph_path @cli.command("run_bot") diff --git a/backend/chatsky_ui/schemas/front_graph_components/base_component.py b/backend/chatsky_ui/schemas/front_graph_components/base_component.py new file mode 100644 index 00000000..6cf3aa88 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/base_component.py @@ -0,0 +1,4 @@ +from pydantic import BaseModel + +class BaseComponent(BaseModel): + pass diff --git a/backend/chatsky_ui/schemas/front_graph_components/flow.py b/backend/chatsky_ui/schemas/front_graph_components/flow.py new file mode 100644 index 00000000..f838e9d9 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/flow.py @@ -0,0 +1,9 @@ +from typing import List + +from .base_component import BaseComponent + + +class Flow(BaseComponent): + name: str + nodes: List[dict] + edges: List[dict] diff --git a/backend/chatsky_ui/schemas/front_graph_components/info_holders/__init__.py b/backend/chatsky_ui/schemas/front_graph_components/info_holders/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py b/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py new file mode 100644 index 00000000..3789472f --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py @@ -0,0 +1,13 @@ +from ..base_component import BaseComponent + + +class Condition(BaseComponent): + name: str + + +class CustomCondition(Condition): + code: str + + +class SlotCondition(Condition): + slot_id: str # not the condition id diff --git a/backend/chatsky_ui/schemas/front_graph_components/info_holders/response.py b/backend/chatsky_ui/schemas/front_graph_components/info_holders/response.py new file mode 100644 index 00000000..53770fcc --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/info_holders/response.py @@ -0,0 +1,13 @@ +from ..base_component import BaseComponent + + +class Response(BaseComponent): + name: str + + +class TextResponse(Response): + text: str + + +class CustomResponse(Response): + code: str diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py new file mode 100644 index 00000000..472fd492 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -0,0 +1,21 @@ +from pydantic import model_validator, RootModel +from typing import Any + +from .base_component import BaseComponent + + +class Interface(BaseComponent, RootModel): + @model_validator(mode="before") + def validate_interface(cls, v): + if not isinstance(v, dict): + raise ValueError('interface must be a dictionary') + if "telegram" in v: + if not isinstance(v['telegram'], dict): + raise ValueError('telegram must be a dictionary') + if 'token' not in v['telegram'] or not isinstance(v['telegram']['token'], str): + raise ValueError('telegram dictionary must contain a string token') + elif "cli" in v: + pass + else: + raise ValueError('interface must contain either telegram or cli') + return v diff --git a/backend/chatsky_ui/schemas/front_graph_components/node.py b/backend/chatsky_ui/schemas/front_graph_components/node.py new file mode 100644 index 00000000..c47e6198 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/node.py @@ -0,0 +1,22 @@ +from typing import List + +from .base_component import BaseComponent + + +class Node(BaseComponent): + id: str + + +class InfoNode(Node): + name: str + response: dict + conditions: List[dict] + + +class LinkNode(Node): + target_flow_name: str + target_node_id: str + + +class SlotsNode(Node): + groups: List[dict] diff --git a/backend/chatsky_ui/schemas/front_graph_components/pipeline.py b/backend/chatsky_ui/schemas/front_graph_components/pipeline.py new file mode 100644 index 00000000..a1c26c86 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/pipeline.py @@ -0,0 +1,8 @@ +from typing import List + +from .base_component import BaseComponent + + +class Pipeline(BaseComponent): + flows: List[dict] + interface: dict diff --git a/backend/chatsky_ui/schemas/front_graph_components/script.py b/backend/chatsky_ui/schemas/front_graph_components/script.py new file mode 100644 index 00000000..42b0cc43 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/script.py @@ -0,0 +1,7 @@ +from typing import List + +from .base_component import BaseComponent + + +class Script(BaseComponent): + flows: List[dict] diff --git a/backend/chatsky_ui/schemas/front_graph_components/slot.py b/backend/chatsky_ui/schemas/front_graph_components/slot.py new file mode 100644 index 00000000..fa1c6580 --- /dev/null +++ b/backend/chatsky_ui/schemas/front_graph_components/slot.py @@ -0,0 +1,16 @@ +from typing import Optional, List + +from .base_component import BaseComponent + +class Slot(BaseComponent): + name: str + + +class RegexpSlot(Slot): + id: str + regexp: str + match_group_idx: Optional[int] + + +class GroupSlot(Slot): + slots: List[dict] diff --git a/backend/chatsky_ui/services/json_converter_new2/base_converter.py b/backend/chatsky_ui/services/json_converter_new2/base_converter.py new file mode 100644 index 00000000..6d654f12 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/base_converter.py @@ -0,0 +1,9 @@ +from abc import ABC, abstractmethod + +class BaseConverter(ABC): + def __call__(self, *args, **kwargs): + return self._convert() + + @abstractmethod + def _convert(self): + raise NotImplementedError diff --git a/backend/chatsky_ui/services/condition_finder.py b/backend/chatsky_ui/services/json_converter_new2/condition_finder.py similarity index 100% rename from backend/chatsky_ui/services/condition_finder.py rename to backend/chatsky_ui/services/json_converter_new2/condition_finder.py diff --git a/backend/chatsky_ui/services/json_converter_new2/consts.py b/backend/chatsky_ui/services/json_converter_new2/consts.py new file mode 100644 index 00000000..d0219028 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/consts.py @@ -0,0 +1,3 @@ +RESPONSES_FILE="responses" +CONDITIONS_FILE="conditions" +CUSTOM_FILE="custom" diff --git a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py new file mode 100644 index 00000000..3dc3ac6e --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py @@ -0,0 +1,68 @@ +from typing import Dict, List, Any, Tuple +from ...schemas.front_graph_components.flow import Flow +from .node_converter import InfoNodeConverter, LinkNodeConverter +from .base_converter import BaseConverter + + +class FlowConverter(BaseConverter): + NODE_CONVERTERS = { + "default_node": InfoNodeConverter, + "link_node": LinkNodeConverter, + } + + def __init__(self, flow: Dict[str, Any]): + self._validate_flow(flow) + self.flow = Flow( + name=flow["name"], + nodes=flow["data"]["nodes"], + edges=flow["data"]["edges"], + ) + + def __call__(self, *args, **kwargs): + self.mapped_flows = kwargs["mapped_flows"] + self.slots_conf = kwargs["slots_conf"] + self._integrate_edges_into_nodes() + return super().__call__(*args, **kwargs) + + def _validate_flow(self, flow: Dict[str, Any]): + if "data" not in flow or "nodes" not in flow["data"] or "edges" not in flow["data"]: + raise ValueError("Invalid flow structure") + + def _integrate_edges_into_nodes(self): + def _insert_dst_into_condition(node: Dict[str, Any], condition_id: str, target_node: Tuple[str, str]) -> Dict[str, Any]: + for condition in node["data"]["conditions"]: + if condition["id"] == condition_id: + condition["dst"] = target_node + return node + + maped_edges = self._map_edges() + nodes = self.flow.nodes.copy() + for edge in maped_edges: + for idx, node in enumerate(nodes): + if node["id"] == edge["source"]: + nodes[idx] = _insert_dst_into_condition(node, edge["sourceHandle"], edge["target"]) + self.flow.nodes = nodes + + def _map_edges(self) -> List[Dict[str, Any]]: + def _get_flow_and_node_names(target_node): + node_type = target_node["type"] + if node_type == "link_node": #TODO: WHY CONVERTING HERE? + return LinkNodeConverter(target_node)(mapped_flows=self.mapped_flows) + elif node_type == "default_node": + return [self.flow.name, target_node["data"]["name"]] + + edges = self.flow.edges.copy() + for edge in edges: + target_id = edge["target"] + # target_node = _find_node_by_id(target_id, self.flow.nodes) + target_node = self.mapped_flows[self.flow.name].get(target_id) + if target_node: + edge["target"] = _get_flow_and_node_names(target_node) + return edges + + def _convert(self) -> Dict[str, Any]: + converted_flow = {self.flow.name: {}} + for node in self.flow.nodes: + if node["type"] == "default_node": + converted_flow[self.flow.name].update({node["data"]["name"]: InfoNodeConverter(node)(slots_conf=self.slots_conf)}) + return converted_flow diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py new file mode 100644 index 00000000..676ad835 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -0,0 +1,9 @@ +from .base_converter import BaseConverter +from ...schemas.front_graph_components.interface import Interface + +class InterfaceConverter(BaseConverter): + def __init__(self, interface: dict): + self.interface = Interface(**interface) + + def _convert(self): + return self.interface.model_dump() diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py new file mode 100644 index 00000000..8c92d3bb --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -0,0 +1,59 @@ +from abc import ABC, abstractmethod +import ast + +from ..consts import CUSTOM_FILE, CONDITIONS_FILE +from ..base_converter import BaseConverter +from ....schemas.front_graph_components.info_holders.condition import CustomCondition, SlotCondition + + +class ConditionConverter(BaseConverter, ABC): + @abstractmethod + def get_pre_transitions(): + raise NotImplementedError + + +class CustomConditionConverter(ConditionConverter): + def __init__(self, condition: dict): + self.condition = CustomCondition( + name=condition["name"], + code=condition["data"]["python"]["action"], + ) + + def _parse_code(self): + condition_code = next(iter(ast.parse(self.condition.code).body)) + + if not isinstance(condition_code, ast.ClassDef): + raise ValueError("Condition python code is not a ClassDef") + return condition_code + + def _convert(self): + custom_cnd = { + f"{CUSTOM_FILE}.{CONDITIONS_FILE}.{self.condition.name}": None + } + return custom_cnd + + def get_pre_transitions(self): + return {} + + +class SlotConditionConverter(ConditionConverter): + def __init__(self, condition: dict): + self.condition = SlotCondition( + slot_id=condition["data"]["slot"], + name=condition["name"] + ) + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return {"chatsky.conditions.slots.SlotsExtracted": self.slots_conf[self.condition.slot_id]} + + def get_pre_transitions(self): + slot_path = self.slots_conf[self.condition.slot_id] + return { + slot_path: { + "chatsky.processing.slots.Extract": slot_path + } + } diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py new file mode 100644 index 00000000..428b30ff --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -0,0 +1,46 @@ +import ast + +from ..base_converter import BaseConverter +from ....schemas.front_graph_components.info_holders.response import TextResponse, CustomResponse +from ..consts import CUSTOM_FILE, RESPONSES_FILE + + +class ResponseConverter(BaseConverter): + pass + + +class TextResponseConverter(ResponseConverter): + def __init__(self, response: dict): + self.response = TextResponse( + name=response["name"], + text=next(iter(response["data"]))["text"], + ) + + def _convert(self): + return { + "chatsky.Message": { + "text": self.response.text + } + } + + +class CustomResponseConverter(ResponseConverter): + def __init__(self, response: dict): + # self.code = + self.response = CustomResponse( + name=response["name"], + code=next(iter(response["data"]))["python"]["action"], + ) + + def _parse_code(self): + response_code = next(iter(ast.parse(self.response.code).body)) + + if not isinstance(response_code, ast.ClassDef): + raise ValueError("Response python code is not a ClassDef") + return response_code + + def _convert(self): + return { + f"{CUSTOM_FILE}.{RESPONSES_FILE}.{self.response.name}": None + } + diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py new file mode 100644 index 00000000..27e4e738 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -0,0 +1,94 @@ +from typing import List + +from .base_converter import BaseConverter +from ...schemas.front_graph_components.node import InfoNode, LinkNode +from .logic_component_converter.response_converter import TextResponseConverter, CustomResponseConverter +from .logic_component_converter.condition_converter import CustomConditionConverter, SlotConditionConverter + +from chatsky import RESPONSE, TRANSITIONS, PRE_TRANSITION + + +class NodeConverter(BaseConverter): + RESPONSE_CONVERTER = { + "text": TextResponseConverter, + "python": CustomResponseConverter, + } + CONDITION_CONVERTER = { + "python": CustomConditionConverter, + "slot": SlotConditionConverter, + } + + def __init__(self, config: dict): + pass + + +class InfoNodeConverter(NodeConverter): + def __init__(self, node: dict): + self.node = InfoNode( + id=node["id"], + name=node["data"]["name"], + response=node["data"]["response"], + conditions=node["data"]["conditions"], + ) + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + condition_converters = [self.CONDITION_CONVERTER[condition["type"]](condition) for condition in self.node.conditions] + return { + RESPONSE: self.RESPONSE_CONVERTER[self.node.response["type"]](self.node.response)(), + TRANSITIONS: [ + { + "dst": condition["dst"], + "priority": condition["data"]["priority"], + "cnd": converter(slots_conf=self.slots_conf) + } for condition, converter in zip(self.node.conditions, condition_converters) + ], + PRE_TRANSITION: { + key: value + for converter in condition_converters + for key, value in converter.get_pre_transitions().items() + } + } + + +class LinkNodeConverter(NodeConverter): + def __init__(self, config: dict): + self.node = LinkNode( + id=config["id"], + target_flow_name=config["data"]["transition"]["target_flow"], + target_node_id=config["data"]["transition"]["target_node"], + ) + + def __call__(self, *args, **kwargs): + self.mapped_flows = kwargs["mapped_flows"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return [ + self.node.target_flow_name, + self.mapped_flows[self.node.target_flow_name][self.node.target_node_id]["data"]["name"], + ] + + +class ConfNodeConverter(NodeConverter): + def __init__(self, config: dict): + super().__init__(config) + + + def _convert(self): + return { + # node.name: node._convert() for node in self.nodes + } + + +class SlotsNodeConverter(ConfNodeConverter): + def __init__(self, config: List[dict]): + self.slots = config + + def _convert(self): + return { + # node.name: node._convert() for node in self.nodes + } diff --git a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py new file mode 100644 index 00000000..c0eeb988 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py @@ -0,0 +1,46 @@ +from pathlib import Path +import yaml +try: + from yaml import CLoader as Loader, CDumper as Dumper +except ImportError: + from yaml import Loader, Dumper + +from ...schemas.front_graph_components.pipeline import Pipeline +from ...schemas.front_graph_components.interface import Interface +from ...schemas.front_graph_components.flow import Flow + +from .base_converter import BaseConverter +from .flow_converter import FlowConverter +from .script_converter import ScriptConverter +from .interface_converter import InterfaceConverter +from .slots_converter import SlotsConverter + + +class PipelineConverter(BaseConverter): + def __init__(self, pipeline_id: int): + self.pipeline_id = pipeline_id + + def __call__(self, input_file: Path, output_dir: Path): + self.from_yaml(file_path=input_file) + self.pipeline = Pipeline(**self.graph) + self.converted_pipeline = super().__call__() + self.to_yaml(dir_path=output_dir) + + def from_yaml(self, file_path: Path): + with open(str(file_path), "r", encoding="UTF-8") as file: + self.graph = yaml.load(file, Loader=Loader) + + def to_yaml(self, dir_path: Path): + with open(f"{dir_path}/build_{self.pipeline_id}.yaml", "w", encoding="UTF-8") as file: + yaml.dump(self.converted_pipeline, file, Dumper=Dumper, default_flow_style=False) + + def _convert(self): + slots_converter = SlotsConverter(self.pipeline.flows) + slots_conf = slots_converter.map_slots() + return { + "script": ScriptConverter(self.pipeline.flows)(slots_conf=slots_conf), + "interface": InterfaceConverter(self.pipeline.interface)(), + "slots": slots_converter(), + # "start_label": self.script.get_start_label(), + # "fallback_label": self.script.get_fallback_label(), + } diff --git a/backend/chatsky_ui/services/json_converter_new2/script_converter.py b/backend/chatsky_ui/services/json_converter_new2/script_converter.py new file mode 100644 index 00000000..6d4a8991 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/script_converter.py @@ -0,0 +1,34 @@ +from typing import List + +from .base_converter import BaseConverter +from .flow_converter import FlowConverter +from ...schemas.front_graph_components.script import Script + + +class ScriptConverter(BaseConverter): + def __init__(self, flows: List[dict]): + self.script = Script(flows=flows) + self.mapped_flows = self._map_flows() #TODO: think about storing this in a temp file + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return { + key: value + for flow in self.script.flows + for key, value in FlowConverter(flow)( + mapped_flows=self.mapped_flows, + slots_conf=self.slots_conf + ).items() + } + + def _map_flows(self): + mapped_flows = {} + for flow in self.script.flows: + mapped_flows[flow["name"]] = {} + for node in flow["data"]["nodes"]: + mapped_flows[flow["name"]][node["id"]] = node + return mapped_flows + diff --git a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py new file mode 100644 index 00000000..7694d8d0 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py @@ -0,0 +1,79 @@ +from typing import List + +from .base_converter import BaseConverter +from ...schemas.front_graph_components.slot import GroupSlot, RegexpSlot +from ...schemas.front_graph_components.node import SlotsNode + +class SlotsConverter(BaseConverter): + def __init__(self, flows: List[dict]): + def _get_slots_node(flows): + return next(iter([ + node + for flow in flows + for node in flow["data"]["nodes"] + if node["type"] == "slots_node" + ])) + + slots_node = _get_slots_node(flows) + self.slots_node = SlotsNode( + id=slots_node["id"], + groups=slots_node["data"]["groups"], + ) + + def map_slots(self): + mapped_slots = {} + for group in self.slots_node.groups.copy(): + for slot in group["slots"]: + mapped_slots[slot["id"]] = ".".join([group["name"], slot["name"]]) + return mapped_slots + + def _convert(self): + return { + key: value + for group in self.slots_node.groups + for key, value in GroupSlotConverter(group)().items() + } + +class RegexpSlotConverter(SlotsConverter): + def __init__(self, slot: dict): + self.slot = RegexpSlot( + id=slot["id"], + name=slot["name"], + regexp=slot["value"], + match_group_idx=slot.get("match_group_idx", None), + ) + + def _convert(self): + return { + self.slot.name: { + "chatksy.slots.RegexpSlot": { + "regexp": self.slot.regexp, + "match_group_idx": self.slot.match_group_idx, + } + } + } + + +class GroupSlotConverter(SlotsConverter): + SLOTS_CONVERTER_TYPES = { + "GroupSlot": "self", # Placeholder, will be replaced in __init__ + "RegexpSlot": RegexpSlotConverter, + } + + def __init__(self, slot: dict): + # Replace the placeholder with the actual class reference + self.SLOTS_CONVERTER_TYPES["GroupSlot"] = GroupSlotConverter + + self.slot = GroupSlot( + name=slot["name"], + slots=slot["slots"], + ) + + def _convert(self): + return { + self.slot.name: { + key: value + for slot in self.slot.slots + for key, value in self.SLOTS_CONVERTER_TYPES[slot["type"]](slot)().items() + } + } From 0b888b5be51fcf82f0e80dbe7ea4f5dfbb82080f Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 11 Oct 2024 17:54:13 +0800 Subject: [PATCH 06/41] refactor: Add store_custom_services --- .../front_graph_components/interface.py | 33 ++++++++++--------- .../schemas/front_graph_components/slot.py | 2 +- .../interface_converter.py | 7 +++- .../condition_converter.py | 10 ++---- .../response_converter.py | 12 ++----- .../service_replacer.py} | 23 ++++++++++--- .../json_converter_new2/pipeline_converter.py | 14 +++++--- .../json_converter_new2/script_converter.py | 20 +++++++++++ .../json_converter_new2/slots_converter.py | 4 +-- 9 files changed, 80 insertions(+), 45 deletions(-) rename backend/chatsky_ui/services/json_converter_new2/{condition_finder.py => logic_component_converter/service_replacer.py} (72%) diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index 472fd492..c5bafbfb 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -1,21 +1,22 @@ -from pydantic import model_validator, RootModel +from pydantic import Field, model_validator from typing import Any from .base_component import BaseComponent +from typing import Optional, Dict +class Interface(BaseComponent): + telegram: Optional[Dict[str, Any]] = Field(default=None) + cli: Optional[Dict[str, Any]] = Field(default=None) -class Interface(BaseComponent, RootModel): - @model_validator(mode="before") - def validate_interface(cls, v): - if not isinstance(v, dict): - raise ValueError('interface must be a dictionary') - if "telegram" in v: - if not isinstance(v['telegram'], dict): - raise ValueError('telegram must be a dictionary') - if 'token' not in v['telegram'] or not isinstance(v['telegram']['token'], str): - raise ValueError('telegram dictionary must contain a string token') - elif "cli" in v: - pass - else: - raise ValueError('interface must contain either telegram or cli') - return v + @model_validator(mode='after') + def check_one_not_none(cls, values): + telegram, cli = values.telegram, values.cli + if (telegram is None) == (cli is None): + raise ValueError('Exactly one of "telegram" or "cli" must be provided.') + return values + + @model_validator(mode='after') + def check_telegram_token(cls, values): + if values.telegram is not None and 'token' not in values.telegram: + raise ValueError('Telegram token must be provided.') + return values diff --git a/backend/chatsky_ui/schemas/front_graph_components/slot.py b/backend/chatsky_ui/schemas/front_graph_components/slot.py index fa1c6580..1ef338d1 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/slot.py +++ b/backend/chatsky_ui/schemas/front_graph_components/slot.py @@ -9,7 +9,7 @@ class Slot(BaseComponent): class RegexpSlot(Slot): id: str regexp: str - match_group_idx: Optional[int] + match_group_idx: int class GroupSlot(Slot): diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py index 676ad835..42ba348a 100644 --- a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -6,4 +6,9 @@ def __init__(self, interface: dict): self.interface = Interface(**interface) def _convert(self): - return self.interface.model_dump() + if self.interface.cli is not None: + return {"chatsky.messengers.console.CLIMessengerInterface": {}} + elif self.interface.telegram is not None: + return { + "chatsky.messengers.telegram.LongpollingInterface": {"token": self.interface.telegram["token"]} + } diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py index 8c92d3bb..0c25737f 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -4,6 +4,8 @@ from ..consts import CUSTOM_FILE, CONDITIONS_FILE from ..base_converter import BaseConverter from ....schemas.front_graph_components.info_holders.condition import CustomCondition, SlotCondition +from ....core.config import settings +from .service_replacer import store_custom_service class ConditionConverter(BaseConverter, ABC): @@ -19,14 +21,8 @@ def __init__(self, condition: dict): code=condition["data"]["python"]["action"], ) - def _parse_code(self): - condition_code = next(iter(ast.parse(self.condition.code).body)) - - if not isinstance(condition_code, ast.ClassDef): - raise ValueError("Condition python code is not a ClassDef") - return condition_code - def _convert(self): + store_custom_service(settings.conditions_path, [self.condition.code]) custom_cnd = { f"{CUSTOM_FILE}.{CONDITIONS_FILE}.{self.condition.name}": None } diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py index 428b30ff..23e92639 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -3,6 +3,8 @@ from ..base_converter import BaseConverter from ....schemas.front_graph_components.info_holders.response import TextResponse, CustomResponse from ..consts import CUSTOM_FILE, RESPONSES_FILE +from ....core.config import settings +from .service_replacer import store_custom_service class ResponseConverter(BaseConverter): @@ -26,21 +28,13 @@ def _convert(self): class CustomResponseConverter(ResponseConverter): def __init__(self, response: dict): - # self.code = self.response = CustomResponse( name=response["name"], code=next(iter(response["data"]))["python"]["action"], ) - def _parse_code(self): - response_code = next(iter(ast.parse(self.response.code).body)) - - if not isinstance(response_code, ast.ClassDef): - raise ValueError("Response python code is not a ClassDef") - return response_code - def _convert(self): + store_custom_service(settings.responses_path, [self.response.code]) return { f"{CUSTOM_FILE}.{RESPONSES_FILE}.{self.response.name}": None } - diff --git a/backend/chatsky_ui/services/json_converter_new2/condition_finder.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py similarity index 72% rename from backend/chatsky_ui/services/json_converter_new2/condition_finder.py rename to backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index 09d94203..4f601fc9 100644 --- a/backend/chatsky_ui/services/json_converter_new2/condition_finder.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -1,6 +1,7 @@ import ast from ast import NodeTransformer from typing import Dict, List +from pathlib import Path from chatsky_ui.core.logger_config import get_logger @@ -13,17 +14,18 @@ def __init__(self, new_services: List[str]): def _get_classes_def(self, services_code: List[str]) -> Dict[str, ast.ClassDef]: parsed_codes = [ast.parse(service_code) for service_code in services_code] - result_nodes = {} for idx, parsed_code in enumerate(parsed_codes): - self._extract_class_defs(parsed_code, result_nodes, services_code[idx]) - return result_nodes + classes = self._extract_class_defs(parsed_code, services_code[idx]) + return classes - def _extract_class_defs(self, parsed_code: ast.Module, result_nodes: Dict[str, ast.ClassDef], service_code: str): + def _extract_class_defs(self, parsed_code: ast.Module, service_code: str): + classes = {} for node in parsed_code.body: if isinstance(node, ast.ClassDef): - result_nodes[node.name] = node + classes[node.name] = node else: logger.error("No class definition found in new_service: %s", service_code) + return classes def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: logger.debug("Visiting class '%s' and comparing with: %s", node.name, self.new_services_classes.keys()) @@ -46,3 +48,14 @@ def _append_new_services(self, node: ast.Module): logger.info("Services not found, appending new services: %s", list(self.new_services_classes.keys())) for _, service in self.new_services_classes.items(): node.body.append(service) + + +def store_custom_service(services_path: Path, services: List[str]): + with open(services_path, "r", encoding="UTF-8") as file: + conditions_tree = ast.parse(file.read()) + + replacer = ServiceReplacer(services) + replacer.visit(conditions_tree) + + with open(services_path, "w") as file: + file.write(ast.unparse(conditions_tree)) diff --git a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py index c0eeb988..210f121f 100644 --- a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py @@ -22,8 +22,10 @@ def __init__(self, pipeline_id: int): def __call__(self, input_file: Path, output_dir: Path): self.from_yaml(file_path=input_file) + self.pipeline = Pipeline(**self.graph) self.converted_pipeline = super().__call__() + self.to_yaml(dir_path=output_dir) def from_yaml(self, file_path: Path): @@ -36,11 +38,15 @@ def to_yaml(self, dir_path: Path): def _convert(self): slots_converter = SlotsConverter(self.pipeline.flows) + script_converter = ScriptConverter(self.pipeline.flows) + slots_conf = slots_converter.map_slots() + start_label, fallback_label = script_converter.extract_start_fallback_labels() + return { - "script": ScriptConverter(self.pipeline.flows)(slots_conf=slots_conf), - "interface": InterfaceConverter(self.pipeline.interface)(), + "script": script_converter(slots_conf=slots_conf), + "messenger_interface": InterfaceConverter(self.pipeline.interface)(), "slots": slots_converter(), - # "start_label": self.script.get_start_label(), - # "fallback_label": self.script.get_fallback_label(), + "start_label": start_label, + "fallback_label": fallback_label, } diff --git a/backend/chatsky_ui/services/json_converter_new2/script_converter.py b/backend/chatsky_ui/services/json_converter_new2/script_converter.py index 6d4a8991..dab6df66 100644 --- a/backend/chatsky_ui/services/json_converter_new2/script_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/script_converter.py @@ -32,3 +32,23 @@ def _map_flows(self): mapped_flows[flow["name"]][node["id"]] = node return mapped_flows + def extract_start_fallback_labels(self): #TODO: refactor this huge method + start_label, fallback_label = None, None + + for flow in self.script.flows: + for node in flow["data"]["nodes"]: + flags = node["data"]["flags"] + + if "start" in flags: + if start_label: + raise ValueError("Multiple start nodes found") + start_label = [flow["name"], node["data"]["name"]] + if "fallback" in flags: + if fallback_label: + raise ValueError("Multiple fallback nodes found") + fallback_label = [flow["name"], node["data"]["name"]] + + if start_label and fallback_label: + return start_label, fallback_label + + return None, None diff --git a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py index 7694d8d0..1966b8d0 100644 --- a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py @@ -40,13 +40,13 @@ def __init__(self, slot: dict): id=slot["id"], name=slot["name"], regexp=slot["value"], - match_group_idx=slot.get("match_group_idx", None), + match_group_idx=slot.get("match_group_idx", 1), ) def _convert(self): return { self.slot.name: { - "chatksy.slots.RegexpSlot": { + "chatsky.slots.RegexpSlot": { "regexp": self.slot.regexp, "match_group_idx": self.slot.match_group_idx, } From 8aa4bd8b2e08c5f2bb2fbd5ab125e07e7b98ec3e Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Sat, 2 Nov 2024 12:40:47 +0800 Subject: [PATCH 07/41] test: Add tests for new json_converter --- .../json_converter_new2/flow_converter.py | 1 - .../condition_converter.py | 30 +++- .../response_converter.py | 26 ++- .../json_converter_new2/node_converter.py | 28 +-- .../json_converter_new2/script_converter.py | 4 +- backend/chatsky_ui/tests/unit/__init__.py | 0 backend/chatsky_ui/tests/unit/conftest.py | 163 ++++++++++++++++++ .../tests/unit/test_flow_converter.py | 146 ++++++++++++++++ .../tests/unit/test_logic_components.py | 95 ++++++++++ .../tests/unit/test_node_converer.py | 44 +++++ .../tests/unit/test_slots_converter.py | 18 ++ backend/poetry.lock | 107 +++++++++++- backend/pyproject.toml | 1 + 13 files changed, 628 insertions(+), 35 deletions(-) create mode 100644 backend/chatsky_ui/tests/unit/__init__.py create mode 100644 backend/chatsky_ui/tests/unit/conftest.py create mode 100644 backend/chatsky_ui/tests/unit/test_flow_converter.py create mode 100644 backend/chatsky_ui/tests/unit/test_logic_components.py create mode 100644 backend/chatsky_ui/tests/unit/test_node_converer.py create mode 100644 backend/chatsky_ui/tests/unit/test_slots_converter.py diff --git a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py index 3dc3ac6e..587033b9 100644 --- a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py @@ -54,7 +54,6 @@ def _get_flow_and_node_names(target_node): edges = self.flow.edges.copy() for edge in edges: target_id = edge["target"] - # target_node = _find_node_by_id(target_id, self.flow.nodes) target_node = self.mapped_flows[self.flow.name].get(target_id) if target_node: edge["target"] = _get_flow_and_node_names(target_node) diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py index 0c25737f..58a450d5 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -8,6 +8,10 @@ from .service_replacer import store_custom_service +class BadConditionException(Exception): + pass + + class ConditionConverter(BaseConverter, ABC): @abstractmethod def get_pre_transitions(): @@ -16,10 +20,14 @@ def get_pre_transitions(): class CustomConditionConverter(ConditionConverter): def __init__(self, condition: dict): - self.condition = CustomCondition( - name=condition["name"], - code=condition["data"]["python"]["action"], - ) + self.condition = None + try: + self.condition = CustomCondition( + name=condition["name"], + code=condition["data"]["python"]["action"], + ) + except KeyError as missing_key: + raise BadConditionException("Missing key in custom condition data") from missing_key def _convert(self): store_custom_service(settings.conditions_path, [self.condition.code]) @@ -34,10 +42,14 @@ def get_pre_transitions(self): class SlotConditionConverter(ConditionConverter): def __init__(self, condition: dict): - self.condition = SlotCondition( - slot_id=condition["data"]["slot"], - name=condition["name"] - ) + self.condition = None + try: + self.condition = SlotCondition( + slot_id=condition["data"]["slot"], + name=condition["name"] + ) + except KeyError as missing_key: + raise BadConditionException("Missing key in slot condition data") from missing_key def __call__(self, *args, **kwargs): self.slots_conf = kwargs["slots_conf"] @@ -47,7 +59,7 @@ def _convert(self): return {"chatsky.conditions.slots.SlotsExtracted": self.slots_conf[self.condition.slot_id]} def get_pre_transitions(self): - slot_path = self.slots_conf[self.condition.slot_id] + slot_path = self.slots_conf[self.condition.slot_id] # type: ignore return { slot_path: { "chatsky.processing.slots.Extract": slot_path diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py index 23e92639..03300db0 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -7,16 +7,23 @@ from .service_replacer import store_custom_service +class BadResponseException(Exception): + pass + + class ResponseConverter(BaseConverter): pass class TextResponseConverter(ResponseConverter): def __init__(self, response: dict): - self.response = TextResponse( - name=response["name"], - text=next(iter(response["data"]))["text"], - ) + try: + self.response = TextResponse( + name=response["name"], + text=next(iter(response["data"]))["text"], + ) + except KeyError as e: + raise BadResponseException("Missing key in custom condition data") from e def _convert(self): return { @@ -28,10 +35,13 @@ def _convert(self): class CustomResponseConverter(ResponseConverter): def __init__(self, response: dict): - self.response = CustomResponse( - name=response["name"], - code=next(iter(response["data"]))["python"]["action"], - ) + try: + self.response = CustomResponse( + name=response["name"], + code=next(iter(response["data"]))["python"]["action"], + ) + except KeyError as e: + raise BadResponseException("Missing key in custom response data") from e def _convert(self): store_custom_service(settings.responses_path, [self.response.code]) diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index 27e4e738..3fd0f4e1 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -73,22 +73,22 @@ def _convert(self): ] -class ConfNodeConverter(NodeConverter): - def __init__(self, config: dict): - super().__init__(config) +# class ConfNodeConverter(NodeConverter): +# def __init__(self, config: dict): +# super().__init__(config) - def _convert(self): - return { - # node.name: node._convert() for node in self.nodes - } +# def _convert(self): +# return { +# # node.name: node._convert() for node in self.nodes +# } -class SlotsNodeConverter(ConfNodeConverter): - def __init__(self, config: List[dict]): - self.slots = config +# class SlotsNodeConverter(ConfNodeConverter): +# def __init__(self, config: List[dict]): +# self.slots = config - def _convert(self): - return { - # node.name: node._convert() for node in self.nodes - } +# def _convert(self): +# return { +# # node.name: node._convert() for node in self.nodes +# } diff --git a/backend/chatsky_ui/services/json_converter_new2/script_converter.py b/backend/chatsky_ui/services/json_converter_new2/script_converter.py index dab6df66..fb10a7fc 100644 --- a/backend/chatsky_ui/services/json_converter_new2/script_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/script_converter.py @@ -37,7 +37,7 @@ def extract_start_fallback_labels(self): #TODO: refactor this huge method for flow in self.script.flows: for node in flow["data"]["nodes"]: - flags = node["data"]["flags"] + flags = node["data"].get("flags", []) if "start" in flags: if start_label: @@ -51,4 +51,4 @@ def extract_start_fallback_labels(self): #TODO: refactor this huge method if start_label and fallback_label: return start_label, fallback_label - return None, None + return start_label, fallback_label#return None, None diff --git a/backend/chatsky_ui/tests/unit/__init__.py b/backend/chatsky_ui/tests/unit/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/backend/chatsky_ui/tests/unit/conftest.py b/backend/chatsky_ui/tests/unit/conftest.py new file mode 100644 index 00000000..bce099a8 --- /dev/null +++ b/backend/chatsky_ui/tests/unit/conftest.py @@ -0,0 +1,163 @@ +import pytest + + +@pytest.fixture +def custom_condition(): + return { + "id": "condition1", + "name": "test_condition", + "type": "python", + "data": { + "priority": 1, + "transition_type": "manual", + "python": { + "action": """class test_condition(BaseCondition):\n async def call(self, ctx: + Context) -> bool:\n return True""" + } + }, + "dst": "dst_test_node", + } + + +@pytest.fixture +def converted_custom_condition(): + return { + "custom.conditions.test_condition": None + } + + +@pytest.fixture +def custom_response(): + return { + "name": "test_response", + "type": "python", + "data": [ + { + "python": { + "action": """class test_response(BaseResponse):\n async def call(self, ctx: + Context) -> Message:\n return Message('Hello')""" + } + } + ] + } + + +@pytest.fixture +def converted_custom_response(): + return { + "custom.responses.test_response": None + } + + +@pytest.fixture +def slots_conf(): + return { + "test_slot": "test_slot" + } + + +# @pytest.fixture +# def converted_pre_transition(): +# return { +# "test_slot": { +# "chatsky.processing.slots.Extract": "test_slot" +# } +# } + + +@pytest.fixture +def regexp_slot(): + return { + "id": "test_slot_id", + "name": "test_slot", + "type": "RegexpSlot", + "value": "test_regexp_value", + "match_group_idx": 1, + } + + +@pytest.fixture +def converted_regexp_slot(): + return { + "test_slot": { + "chatsky.slots.RegexpSlot": { + "regexp": "test_regexp_value", + "match_group_idx": 1, + } + } + } + + +@pytest.fixture +def group_slot(regexp_slot): + return { + "name": "group_slot", + "slots": [regexp_slot] + } + + +@pytest.fixture +def converted_group_slot(converted_regexp_slot): + return { + "group_slot": converted_regexp_slot + } + + +@pytest.fixture +def info_node(custom_response, custom_condition): + return { + "id": "1", + "type": "default_node", + "data": { + "name": "test_node", + "response": custom_response, + "conditions": [ + custom_condition + ], + "flags": ["start", "fallback"], + } + } + + +@pytest.fixture +def flow(info_node, group_slot): + return { + "name": "test_flow", + "data": { + "nodes": [ + info_node, + { + "type": "slots_node", + "id": "test_slots_node_id", + "data": { + "groups": [group_slot] + } + }, + ], + "edges": [ + { + "source": "1", + "sourceHandle": "1", + "target": "1" + } + ] + } + } + + +@pytest.fixture +def mapped_flow(info_node): + return { + "test_flow": { + "1": info_node + } + } + + +@pytest.fixture +def telegram_interface(): + return { + "telegram": { + "token": "test_token", + } + } \ No newline at end of file diff --git a/backend/chatsky_ui/tests/unit/test_flow_converter.py b/backend/chatsky_ui/tests/unit/test_flow_converter.py new file mode 100644 index 00000000..c47a015e --- /dev/null +++ b/backend/chatsky_ui/tests/unit/test_flow_converter.py @@ -0,0 +1,146 @@ +import pytest +from pathlib import Path +import yaml + +from chatsky_ui.services.json_converter_new2.flow_converter import FlowConverter +from chatsky_ui.services.json_converter_new2.script_converter import ScriptConverter +from chatsky_ui.services.json_converter_new2.interface_converter import InterfaceConverter +from chatsky_ui.services.json_converter_new2.pipeline_converter import PipelineConverter + + + +@pytest.fixture +def chatsky_flow(): + return { + "test_flow": { + "test_node": { + "RESPONSE": { + "custom.responses.test_response": None + }, + "TRANSITIONS": [ + { + "cnd": { + "custom.conditions.test_condition": None + }, + "dst": "dst_test_node", + "priority": 1, + } + ], + "PRE_TRANSITION": {}, + } + } + } + + +class TestFlowConverter: + def test_flow_converter(self, flow, mapped_flow, slots_conf, chatsky_flow): + converted_flow = FlowConverter(flow)(mapped_flows=mapped_flow, slots_conf=slots_conf) + + assert converted_flow == chatsky_flow + + + def test_flow_converter_fail_no_nodes(self, flow, mapped_flow, slots_conf): + del flow["data"]["nodes"] + with pytest.raises(ValueError): + FlowConverter(flow) + + def test_flow_converter_fail_no_edges(self, flow, mapped_flow, slots_conf): + del flow["data"]["edges"] + + with pytest.raises(ValueError): + FlowConverter(flow) + + +class TestScriptConverter: + def test_script_converter(self, flow, slots_conf, chatsky_flow): + converted_script = ScriptConverter([flow])(slots_conf=slots_conf) + + assert converted_script == chatsky_flow + + def test_extract_start_fallback_labels(self, flow, slots_conf): + converter = ScriptConverter([flow]) + converter(slots_conf=slots_conf) + + start, fallback = converter.extract_start_fallback_labels() + + assert start + assert fallback + + def test_extract_start_fallback_labels_fail_no_labels(self, flow, slots_conf): + flow["data"]["nodes"][0]["data"]["flags"] = [] + converter = ScriptConverter([flow]) + converter(slots_conf=slots_conf) + + start, fallback = converter.extract_start_fallback_labels() + + assert not start + assert not fallback + + def test_extract_start_fallback_labels_fail_multiple_labels(self, flow, slots_conf): + flow["data"]["nodes"][0]["data"]["flags"] = ["start"] + flow["data"]["nodes"][1]["data"]["flags"] = ["start"] + converter = ScriptConverter([flow]) + converter(slots_conf=slots_conf) + + with pytest.raises(ValueError): + converter.extract_start_fallback_labels() + +class TestInterfaceConverter: + def test_interface_converter(self, telegram_interface): + interface = telegram_interface + + converted_interface = InterfaceConverter(interface)() + + assert converted_interface == { + "chatsky.messengers.telegram.LongpollingInterface": { + "token": "test_token", + } + } + + def test_interface_fail_no_token(self): + interface = { + "telegram": {} + } + + with pytest.raises(ValueError): + InterfaceConverter(interface)() + + + def test_interface_fail_multiple_interfaces(self, telegram_interface): + interface = { + **telegram_interface, + "cli": {} + } + + with pytest.raises(ValueError): + InterfaceConverter(interface)() + + +class TestPipelineConverter: + def test_pipeline_converter(self, flow, telegram_interface, converted_group_slot, chatsky_flow): + pipeline = { + "flows": [flow], + "interface": telegram_interface + } + pipeline_path = Path(__file__).parent / "test_pipeline.yaml" + with open(pipeline_path, "w") as file: + yaml.dump(pipeline, file) + + PipelineConverter(pipeline_id=1)(pipeline_path, Path(__file__).parent) + + output_file = Path(__file__).parent / "build_1.yaml" + with open(output_file) as file: + converted_pipeline = yaml.load(file, Loader=yaml.Loader) + output_file.unlink() + + assert converted_pipeline == { + "script": chatsky_flow, + "messenger_interface": { + "chatsky.messengers.telegram.LongpollingInterface": { + "token": "test_token", + } + }, + "slots": converted_group_slot, + "start_label": ["test_flow", "test_node"], + "fallback_label": ["test_flow", "test_node"], + } diff --git a/backend/chatsky_ui/tests/unit/test_logic_components.py b/backend/chatsky_ui/tests/unit/test_logic_components.py new file mode 100644 index 00000000..c6f53735 --- /dev/null +++ b/backend/chatsky_ui/tests/unit/test_logic_components.py @@ -0,0 +1,95 @@ +import pytest +from chatsky_ui.services.json_converter_new2.logic_component_converter.condition_converter import ( + CustomConditionConverter, SlotConditionConverter, BadConditionException +) +from chatsky_ui.services.json_converter_new2.logic_component_converter.response_converter import ( + TextResponseConverter, CustomResponseConverter, BadResponseException +) +from chatsky_ui.services.json_converter_new2.logic_component_converter.service_replacer import store_custom_service +from pathlib import Path + + +@pytest.fixture +def slot_condition(): + return { + "name": "test_condition", + "data": { + "slot": "test_slot" + } + } + +@pytest.fixture +def text_response(): + return { + "name": "test_response", + "data": [ + { + "text": "test_text" + } + ] + } + + +class TestConditionConverter: + def test_custom_condition_converter(self, custom_condition, converted_custom_condition): + converted_cnd = CustomConditionConverter(custom_condition)() + assert converted_cnd == converted_custom_condition + + def test_custom_condition_converter_fail(self, slot_condition): + with pytest.raises(BadConditionException): + CustomConditionConverter(slot_condition)() + + def test_slot_condition_converter(self, slot_condition, slots_conf): + converted_cnd = SlotConditionConverter(slot_condition)(slots_conf=slots_conf) + assert converted_cnd == { + "chatsky.conditions.slots.SlotsExtracted": "test_slot" + } + + def test_slot_condition_converter_fail(self, custom_condition): + with pytest.raises(BadConditionException): + SlotConditionConverter(custom_condition)() + + def test_slot_condition_converter_get_pre_transitions(self, slot_condition, slots_conf): + converter = SlotConditionConverter(slot_condition) + converter(slots_conf=slots_conf) + assert converter.get_pre_transitions() == { + "test_slot": { + "chatsky.processing.slots.Extract": "test_slot" + } + } + + +class TestResponseConverter: + def test_text_response_converter(self, text_response): + converted_response = TextResponseConverter(text_response)() + assert converted_response == { + "chatsky.Message": { + "text": "test_text" + } + } + + def test_text_response_converter_fail(self, custom_response): + with pytest.raises(BadResponseException): + TextResponseConverter(custom_response)() + + def test_custom_response_converter(self, custom_response, converted_custom_response): + converted_response = CustomResponseConverter(custom_response)() + assert converted_response == converted_custom_response + + def test_custom_response_converter_fail(self, text_response): + with pytest.raises(BadResponseException): + CustomResponseConverter(text_response)() + + +def test_store_custom_service(): + current_file_path = Path(__file__).resolve() + service_code = """class test_service(BaseService):\n async def call(self, ctx: + Context) -> Message:\n return Message('Hello')""" + test_file_path = current_file_path.parent / "store_service_test.py" + test_file_path.touch(exist_ok=True) + + try: + store_custom_service(test_file_path, [service_code]) + assert test_file_path.stat().st_size > 0 # Check that the file is not empty + finally: + test_file_path.unlink() # Clean up diff --git a/backend/chatsky_ui/tests/unit/test_node_converer.py b/backend/chatsky_ui/tests/unit/test_node_converer.py new file mode 100644 index 00000000..471d60c1 --- /dev/null +++ b/backend/chatsky_ui/tests/unit/test_node_converer.py @@ -0,0 +1,44 @@ +import pytest + +from chatsky_ui.services.json_converter_new2.node_converter import InfoNodeConverter, LinkNodeConverter + + +class TestNodeConverter: + def test_info_node_converter(self, info_node, slots_conf, converted_custom_response, converted_custom_condition): + converted_node = InfoNodeConverter(info_node)(slots_conf=slots_conf) + + assert converted_node == { + "RESPONSE": converted_custom_response, + "TRANSITIONS": [ + { + "dst": "dst_test_node", + "priority": 1, + "cnd": converted_custom_condition + } + ], + "PRE_TRANSITION": {}, + } + + def test_link_node_converter(self): + link_node = { + "id": "test_link_node", + "data": { + "transition": { + "target_flow": "test_flow", + "target_node": "test_node_id" + } + } + } + mapped_flows = { + "test_flow": { + "test_node_id": { + "data": { + "name": "test_node" + } + } + } + } + + converted_node = LinkNodeConverter(link_node)(mapped_flows=mapped_flows) + + assert converted_node == ["test_flow", "test_node"] diff --git a/backend/chatsky_ui/tests/unit/test_slots_converter.py b/backend/chatsky_ui/tests/unit/test_slots_converter.py new file mode 100644 index 00000000..44df3dfd --- /dev/null +++ b/backend/chatsky_ui/tests/unit/test_slots_converter.py @@ -0,0 +1,18 @@ +from chatsky_ui.services.json_converter_new2.slots_converter import SlotsConverter, RegexpSlotConverter, GroupSlotConverter + + +class TestSlotsConverter: + def test_slots_converter(self, flow, converted_group_slot): + converted_slots = SlotsConverter([flow])() + + assert converted_slots == converted_group_slot + + def test_regexp_slot_converter(self, regexp_slot, converted_regexp_slot): + converted_slot = RegexpSlotConverter(regexp_slot)() + + assert converted_slot == converted_regexp_slot + + def test_group_slot_converter(self, group_slot, converted_group_slot): + converted_slot = GroupSlotConverter(group_slot)() + + assert converted_slot == converted_group_slot diff --git a/backend/poetry.lock b/backend/poetry.lock index a8ad839b..0b408ab2 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -526,6 +526,93 @@ pyyaml = ">=5.3.1" requests = ">=2.23.0" rich = "*" +[[package]] +name = "coverage" +version = "7.6.1" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.8" +files = [ + {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, + {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, + {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, + {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, + {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, + {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, + {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, + {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, + {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, + {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, + {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, + {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, + {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, + {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, + {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, + {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, + {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, + {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, + {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, + {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, + {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, + {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, + {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, + {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, + {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, + {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, + {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, + {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, + {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, + {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, + {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, + {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, + {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, + {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, + {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, + {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, + {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, + {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "cryptography" version = "43.0.1" @@ -1358,6 +1445,24 @@ pytest = ">=7.0.0,<9" docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] +[[package]] +name = "pytest-cov" +version = "5.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.8" +files = [ + {file = "pytest-cov-5.0.0.tar.gz", hash = "sha256:5837b58e9f6ebd335b0f8060eecce69b662415b16dc503883a02f45dfeb14857"}, + {file = "pytest_cov-5.0.0-py3-none-any.whl", hash = "sha256:4f0764a1219df53214206bf1feea4633c3b558a2925c8b59f144f682861ce652"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "virtualenv"] + [[package]] name = "pytest-mock" version = "3.14.0" @@ -2281,4 +2386,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "c74907728cefa15f4c599238fa17b5f174afa6f54e483e75e9a4388265462f51" +content-hash = "dd95fdb7eb30fc9fa546929eb6640e86455faf4e16c6ca8c149efa2edffe4165" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 4d7017f1..016cd94c 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -30,6 +30,7 @@ httpx-ws = "^0.6.0" pylint = "^3.2.3" sphinx = "*" sphinx-rtd-theme = "*" +pytest-cov = "^5.0.0" [tool.poetry.scripts] "chatsky.ui" = "chatsky_ui.cli:cli" From 43e3ff6071db3a03953eabb7b30a28898f8bf5ea Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 5 Nov 2024 14:12:30 +0800 Subject: [PATCH 08/41] fix: Handle building if there's no slot_node in graph --- backend/chatsky_ui/services/json_converter.py | 281 ------------------ .../json_converter_new2/slots_converter.py | 2 +- 2 files changed, 1 insertion(+), 282 deletions(-) delete mode 100644 backend/chatsky_ui/services/json_converter.py diff --git a/backend/chatsky_ui/services/json_converter.py b/backend/chatsky_ui/services/json_converter.py deleted file mode 100644 index 73cc1824..00000000 --- a/backend/chatsky_ui/services/json_converter.py +++ /dev/null @@ -1,281 +0,0 @@ -""" -JSON Converter ---------------- - -Converts a user project's frontend graph to a script understandable by Chatsky json-importer. -""" -import ast -from collections import defaultdict -from pathlib import Path -from typing import List, Optional, Tuple - -from omegaconf.dictconfig import DictConfig - -from chatsky_ui.core.config import settings -from chatsky_ui.core.logger_config import get_logger -from chatsky_ui.db.base import read_conf, write_conf -from chatsky_ui.services.condition_finder import ServiceReplacer - -logger = get_logger(__name__) - -PRE_TRANSITIONS_PROCESSING = "PRE_TRANSITIONS_PROCESSING" - - -PRE_TRANSITION = "PRE_TRANSITION" - - -def _get_db_paths(build_id: int) -> Tuple[Path, Path, Path, Path]: - """Get paths to frontend graph, chatsky script, and chatsky custom conditions files.""" - frontend_graph_path = settings.frontend_flows_path - custom_conditions_file = settings.conditions_path - custom_responses_file = settings.responses_path - script_path = settings.scripts_dir / f"build_{build_id}.yaml" - - if not frontend_graph_path.exists(): - raise FileNotFoundError(f"File {frontend_graph_path} doesn't exist") - if not custom_conditions_file.exists(): - raise FileNotFoundError(f"File {custom_conditions_file} doesn't exist") - if not custom_responses_file.exists(): - raise FileNotFoundError(f"File {custom_responses_file} doesn't exist") - if not script_path.exists(): - script_path.parent.mkdir(parents=True, exist_ok=True) - script_path.touch() - - return frontend_graph_path, script_path, custom_conditions_file, custom_responses_file - - -def _organize_graph_according_to_nodes(flow_graph: DictConfig, script: dict) -> Tuple[dict, dict]: - nodes = {} - for flow in flow_graph["flows"]: - node_names_in_one_flow = [] - for node in flow.data.nodes: - if "flags" in node.data: - if "start" in node.data.flags: - if "start_label" in script: - raise ValueError("There are more than one start node in the script") - script["start_label"] = [flow.name, node.data.name] - if "fallback" in node.data.flags: - if "fallback_label" in script: - raise ValueError("There are more than one fallback node in the script") - script["fallback_label"] = [flow.name, node.data.name] - - if node.data.name in node_names_in_one_flow: - raise ValueError(f"There is more than one node with the name '{node.data.name}' in the same flow.") - node_names_in_one_flow.append(node.data.name) - nodes[node.id] = {"info": node} - nodes[node.id]["flow"] = flow.name - nodes[node.id]["TRANSITIONS"] = [] - nodes[node.id][PRE_TRANSITION] = dict() - - def _convert_slots(slots: dict) -> dict: - group_slot = defaultdict(dict) - for slot_name, slot_values in slots.copy().items(): - slot_type = slot_values["type"] - del slot_values["id"] - del slot_values["type"] - if slot_type != "GroupSlot": - group_slot[slot_name].update({f"chatsky.slots.{slot_type}": {k: v for k, v in slot_values.items()}}) - else: - group_slot[slot_name] = _convert_slots(slot_values) - return dict(group_slot) - - if "slots" in flow_graph: - script["slots"] = _convert_slots(flow_graph["slots"]) - - return nodes, script - - -def _get_condition(nodes: dict, edge: DictConfig) -> Optional[DictConfig]: - """Get node's condition from `nodes` according to `edge` info.""" - return next( - (condition for condition in nodes[edge.source]["info"].data.conditions if condition["id"] == edge.sourceHandle), - None, - ) - - -def _add_transitions(nodes: dict, edge: DictConfig, condition: DictConfig, slots: DictConfig) -> None: - """Add transitions to a node according to `edge` and `condition`.""" - - def _get_slot(slots, id_): - if not slots: - return "" - for name, value in slots.copy().items(): - slot_path = name - if value.get("id") == id_: - return name - elif value.get("type") != "GroupSlot": - continue - else: - del value["id"] - del value["type"] - slot_path = _get_slot(value, id_) - if slot_path: - slot_path = ".".join([name, slot_path]) - return slot_path - - if condition["type"] == "python": - converted_cnd = {f"custom.conditions.{condition.name}": None} - elif condition["type"] == "slot": - slot = _get_slot(slots, id_=condition.data.slot) - converted_cnd = {"chatsky.conditions.slots.SlotsExtracted": slot} - nodes[edge.source][PRE_TRANSITION].update({slot: {"chatsky.processing.slots.Extract": slot}}) - # TODO: elif condition["type"] == "chatsky": - else: - raise ValueError(f"Unknown condition type: {condition['type']}") - - # if the edge is a link_node, we add transition of its source and target - if nodes[edge.target]["info"].type == "link_node": - flow = nodes[edge.target]["info"].data.transition.target_flow - - target_node = nodes[edge.target]["info"].data.transition.target_node - node = nodes[target_node]["info"].data.name - else: - flow = nodes[edge.target]["flow"] - node = nodes[edge.target]["info"].data.name - - nodes[edge.source]["TRANSITIONS"].append( - { - "dst": [ - flow, - node, - ], - "priority": condition.data.priority, - "cnd": converted_cnd, - } - ) - - -def _fill_nodes_into_script(nodes: dict, script: dict) -> None: - """Fill nodes into chatsky script dictunary.""" - for _, node in nodes.items(): - if node["info"].type in ["link_node", "slots_node"]: - continue - if node["flow"] not in script["script"]: - script["script"][node["flow"]] = {} - script["script"][node["flow"]].update( - { - node["info"].data.name: { - "RESPONSE": node["info"].data.response, - "TRANSITIONS": node["TRANSITIONS"], - PRE_TRANSITION: node[PRE_TRANSITION], - } - } - ) - - -async def update_responses_lines(nodes: dict) -> Tuple[dict, List[str]]: - """Organizes the responses in nodes in a format that json-importer accepts. - - If the response type is "python", its function will be added to responses_lines to be written - to the custom_conditions_file later. - * If the response already exists in the responses_lines, it will be replaced with the new one. - """ - responses_list = [] - for node in nodes.values(): - if node["info"].type in ["link_node", "slots_node"]: - continue - response = node["info"].data.response - logger.debug("response type: %s", response.type) - if response.type == "python": - response.data = response.data[0] - logger.info("Adding response: %s", response) - - responses_list.append(response.data.python.action) - node["info"].data.response = {f"custom.responses.{response.name}": None} - elif response.type == "text": - response.data = response.data[0] - logger.debug("Adding response: %s", response.data.text) - node["info"].data.response = {"chatsky.Message": {"text": response.data.text}} - elif response.type == "choice": - # logger.debug("Adding response: %s", ) - chatsky_responses = [] - for message in response.data: - if "text" in message: - chatsky_responses.append({"chatsky.Message": {"text": message["text"]}}) - else: # TODO: check: are you sure that you can use only "text" type inside a choice? - raise ValueError("Unknown response type. There must be a 'text' field in each message.") - node["info"].data.response = {"chatsky.rsp.choice": chatsky_responses.copy()} - else: - raise ValueError(f"Unknown response type: {response.type}") - return nodes, responses_list - - -def map_interface(interface: DictConfig) -> dict: - """Map frontend interface to chatsky interface.""" - if not isinstance(interface, DictConfig): - raise ValueError(f"Interface must be a dictionary. Got: {type(interface)}") - keys = interface.keys() - if len(keys) != 1: - raise ValueError("There must be only one key in the interface") - - key = next(iter(keys)) - if key == "telegram": - if "token" not in interface[key]: - raise ValueError("Token keyworkd is not provided for telegram interface") - if not interface[key]["token"]: - raise ValueError("Token is not provided for telegram interface") - return {"chatsky.messengers.telegram.LongpollingInterface": {"token": interface[key]["token"]}} - if key == "cli": - return {"chatsky.messengers.console.CLIMessengerInterface": {}} - else: - raise ValueError(f"Unknown interface: {key}") - - -async def converter(build_id: int) -> None: - """Translate frontend flow script into chatsky script.""" - frontend_graph_path, script_path, custom_conditions_file, custom_responses_file = _get_db_paths(build_id) - - flow_graph: DictConfig = await read_conf(frontend_graph_path) # type: ignore - script = { - "script": {}, - "messenger_interface": map_interface(flow_graph["interface"]), - } - del flow_graph["interface"] - - nodes, script = _organize_graph_according_to_nodes(flow_graph, script) - - with open(custom_responses_file, "r", encoding="UTF-8") as file: - responses_tree = ast.parse(file.read()) - - nodes, responses_list = await update_responses_lines(nodes) - - logger.info("Responses list: %s", responses_list) - replacer = ServiceReplacer(responses_list) - replacer.visit(responses_tree) - - with open(custom_responses_file, "w") as file: - file.write(ast.unparse(responses_tree)) - - with open(custom_conditions_file, "r", encoding="UTF-8") as file: - conditions_tree = ast.parse(file.read()) - - conditions_list = [] - - for flow in flow_graph["flows"]: - for edge in flow.data.edges: - if edge.source in nodes and edge.target in nodes: - condition = _get_condition(nodes, edge) - if condition is None: - logger.error( - "A condition of edge '%s' - '%s' and id of '%s' is not found in the corresponding node", - edge.source, - edge.target, - edge.sourceHandle, - ) - continue - if condition.type == "python": - conditions_list.append(condition.data.python.action) - - _add_transitions(nodes, edge, condition, flow_graph["slots"]) - else: - logger.error("A node of edge '%s-%s' is not found in nodes", edge.source, edge.target) - - replacer = ServiceReplacer(conditions_list) - replacer.visit(conditions_tree) - - with open(custom_conditions_file, "w") as file: - file.write(ast.unparse(conditions_tree)) - - _fill_nodes_into_script(nodes, script) - - await write_conf(script, script_path) diff --git a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py index 1966b8d0..fc3e38aa 100644 --- a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py @@ -12,7 +12,7 @@ def _get_slots_node(flows): for flow in flows for node in flow["data"]["nodes"] if node["type"] == "slots_node" - ])) + ]), {"id": "999999", "data": {"groups": []}}) slots_node = _get_slots_node(flows) self.slots_node = SlotsNode( From c75b014b2fe70cd57bf6b4228fab5c493e6fc054 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 5 Nov 2024 18:40:54 +0800 Subject: [PATCH 09/41] refactor: Add dev group in toml file --- backend/poetry.lock | 2 +- backend/pyproject.toml | 17 +++++++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index 0b408ab2..5112e4df 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -2386,4 +2386,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.8.1" -content-hash = "dd95fdb7eb30fc9fa546929eb6640e86455faf4e16c6ca8c149efa2edffe4165" +content-hash = "e304dd375781fd496f300fa8fd8ba2ad3e1d9c1d8bbdb41504cea83941bc247d" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 016cd94c..73631092 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -22,15 +22,9 @@ aiofiles = "^23.2.1" cookiecutter = "^2.6.0" chatsky = {version = "1.0.0rc1", extras = ["yaml", "telegram"]} omegaconf = "^2.3.0" -pytest = "^8.1.1" -pytest-asyncio = "^0.23.6" -pytest-mock = "^3.14.0" httpx = "^0.27.0" httpx-ws = "^0.6.0" pylint = "^3.2.3" -sphinx = "*" -sphinx-rtd-theme = "*" -pytest-cov = "^5.0.0" [tool.poetry.scripts] "chatsky.ui" = "chatsky_ui.cli:cli" @@ -42,3 +36,14 @@ optional = true isort = "^5" black = "^22" flake8 = "^4" + +[tool.poetry.group.dev] +optional = true + +[tool.poetry.group.dev.dependencies] +pytest = "^8.1.1" +pytest-asyncio = "^0.23.6" +pytest-mock = "^3.14.0" +sphinx = "*" +sphinx-rtd-theme = "*" +pytest-cov = "^5.0.0" From 6727a18544ba694fda3b37f460d5393f8f9712b1 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 5 Nov 2024 18:42:45 +0800 Subject: [PATCH 10/41] refactor: Use ast instead of the manual old indexing --- .../chatsky_ui/api/api_v1/endpoints/bot.py | 4 +- .../api/api_v1/endpoints/chatsky_services.py | 23 ++- backend/chatsky_ui/api/deps.py | 10 - backend/chatsky_ui/core/config.py | 1 - backend/chatsky_ui/main.py | 5 - backend/chatsky_ui/services/index.py | 185 ------------------ .../service_replacer.py | 10 + .../chatsky_ui/services/process_manager.py | 4 +- docs/appref/chatsky_ui/services.rst | 8 - 9 files changed, 26 insertions(+), 224 deletions(-) delete mode 100644 backend/chatsky_ui/services/index.py diff --git a/backend/chatsky_ui/api/api_v1/endpoints/bot.py b/backend/chatsky_ui/api/api_v1/endpoints/bot.py index a053f3b4..6f0df7ee 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/bot.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/bot.py @@ -7,7 +7,6 @@ from chatsky_ui.schemas.pagination import Pagination from chatsky_ui.schemas.preset import Preset from chatsky_ui.schemas.process_status import Status -from chatsky_ui.services.index import Index from chatsky_ui.services.process_manager import BuildManager, ProcessManager, RunManager from chatsky_ui.services.websocket_manager import WebSocketManager @@ -45,7 +44,6 @@ async def start_build( preset: Preset, background_tasks: BackgroundTasks, build_manager: BuildManager = Depends(deps.get_build_manager), - index: Index = Depends(deps.get_index), ) -> Dict[str, Union[str, int]]: """Starts a `build` process with the given preset. @@ -61,7 +59,7 @@ async def start_build( await asyncio.sleep(preset.wait_time) build_id = await build_manager.start(preset) - background_tasks.add_task(build_manager.check_status, build_id, index) + background_tasks.add_task(build_manager.check_status, build_id) build_manager.logger.info("Build process '%s' has started", build_id) return {"status": "ok", "build_id": build_id} diff --git a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py index 612a8e0d..8b21cd5f 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py @@ -1,3 +1,4 @@ +import ast import re from io import StringIO from typing import Dict, Optional, Union @@ -7,26 +8,30 @@ from pylint.lint import Run, pylinter from pylint.reporters.text import TextReporter -from chatsky_ui.api.deps import get_index from chatsky_ui.clients.chatsky_client import get_chatsky_conditions from chatsky_ui.core.config import settings from chatsky_ui.schemas.code_snippet import CodeSnippet -from chatsky_ui.services.index import Index +from chatsky_ui.services.json_converter_new2.logic_component_converter.service_replacer import get_all_classes from chatsky_ui.utils.ast_utils import get_imports_from_file router = APIRouter() -@router.get("/search/{service_name}", status_code=200) -async def search_service(service_name: str, index: Index = Depends(get_index)) -> Dict[str, Optional[Union[str, list]]]: - """Searches for a custom service by name and returns its code. - - A service could be a condition, reponse, or pre/postservice. - """ - response = await index.search_service(service_name) +@router.get("/search/condition/{condition_name}", status_code=200) +async def search_condition(condition_name: str) -> Dict[str, Union[str, list]]: + """Searches for a custom condition by name and returns its code.""" + custom_classes = get_all_classes(settings.conditions_path) + response = [custom_class["body"] for custom_class in custom_classes if custom_class["name"] == condition_name] return {"status": "ok", "data": response} +@router.get("/get_all_custom_conditions", status_code=200) +async def get_all_custom_conditions_names() -> Dict[str, Union[str, list]]: + all_classes = get_all_classes(settings.conditions_path) + custom_classes = [custom_class["body"] for custom_class in all_classes] + return {"status": "ok", "data": custom_classes} + + @router.post("/lint_snippet", status_code=200) async def lint_snippet(snippet: CodeSnippet) -> Dict[str, str]: """Lints a snippet with Pylint. diff --git a/backend/chatsky_ui/api/deps.py b/backend/chatsky_ui/api/deps.py index 7317d638..276d9474 100644 --- a/backend/chatsky_ui/api/deps.py +++ b/backend/chatsky_ui/api/deps.py @@ -1,5 +1,4 @@ from chatsky_ui.core.config import settings -from chatsky_ui.services.index import Index from chatsky_ui.services.process_manager import BuildManager, RunManager from chatsky_ui.services.websocket_manager import WebSocketManager @@ -25,12 +24,3 @@ def get_run_manager() -> RunManager: def get_websocket_manager() -> WebSocketManager: websocket_manager.set_logger() return websocket_manager - - -index = Index() - - -def get_index() -> Index: - index.set_logger() - index.set_path(settings.index_path) - return index diff --git a/backend/chatsky_ui/core/config.py b/backend/chatsky_ui/core/config.py index 30cd10a9..b1daeb24 100644 --- a/backend/chatsky_ui/core/config.py +++ b/backend/chatsky_ui/core/config.py @@ -49,7 +49,6 @@ def _set_user_proj_paths(self): self.snippet2lint_path = self.work_directory / "chatsky_ui/.snippet2lint.py" self.custom_dir = self.work_directory / "bot/custom" - self.index_path = self.custom_dir / ".services_index.yaml" self.conditions_path = self.custom_dir / "conditions.py" self.responses_path = self.custom_dir / "responses.py" self.scripts_dir = self.work_directory / "bot/scripts" diff --git a/backend/chatsky_ui/main.py b/backend/chatsky_ui/main.py index 8bb10362..49a0f868 100644 --- a/backend/chatsky_ui/main.py +++ b/backend/chatsky_ui/main.py @@ -6,19 +6,14 @@ from chatsky_ui import __version__ from chatsky_ui.api.api_v1.api import api_router -from chatsky_ui.api.deps import get_index from chatsky_ui.core.config import settings -index_dict = {} - @asynccontextmanager async def lifespan(app: FastAPI): if settings.temp_conf.exists(): settings.refresh_work_dir() - index_dict["instance"] = get_index() - await index_dict["instance"].load() yield # settings.temp_conf.unlink(missing_ok=True) diff --git a/backend/chatsky_ui/services/index.py b/backend/chatsky_ui/services/index.py deleted file mode 100644 index 05427c41..00000000 --- a/backend/chatsky_ui/services/index.py +++ /dev/null @@ -1,185 +0,0 @@ -""" -Index service -------------- - -The Index service is responsible for indexing the user bot's conditions, responses, and services. -By indexing the project, the Index service creates an in-memory representation that can be -quickly accessed when needed. -""" -import asyncio -from pathlib import Path -from typing import Dict, List, Optional - -from omegaconf import OmegaConf -from omegaconf.dictconfig import DictConfig - -from chatsky_ui.core.config import settings -from chatsky_ui.core.logger_config import get_logger -from chatsky_ui.db.base import read_conf, read_logs, write_conf - - -class Index: - def __init__(self): - self.index: dict = {} - self.conditions: List[str] = [] - self.responses: List[str] = [] - self.services: List[str] = [] - self._logger = None - self._path = None - - @property - def logger(self): - if self._logger is None: - raise ValueError("Logger has not been configured. Call set_logger() first.") - return self._logger - - def set_logger(self): - self._logger = get_logger(__name__) - - @property - def path(self): - if self._path is None: - raise ValueError("Path has not been configured. Call set_path() first.") - return self._path - - def set_path(self, path: Path): - self._path = path - - async def _load_index(self) -> None: - """Load indexed conditions, responses and services from disk.""" - db_index: DictConfig = await read_conf(self.path) # type: ignore - index_dict: Dict[str, dict] = OmegaConf.to_container(db_index, resolve=True) # type: ignore - self.index = index_dict - self.logger.debug("Index loaded") - - async def _load_conditions(self) -> None: - """Load conditions from disk.""" - path = settings.conditions_path - if path.exists(): - self.conditions = await read_logs(path) - self.logger.debug("Conditions loaded") - else: - self.logger.warning("No conditions file found") - - async def _load_responses(self) -> None: - """Load responses from disk.""" - path = settings.responses_path - if path.exists(): - self.responses = await read_logs(path) - self.logger.debug("Responses loaded") - else: - self.logger.warning("No responses file found") - - async def _load_services(self) -> None: - """Load services from disk.""" - path = settings.responses_path.parent / "services.py" - if path.exists(): - self.services = await read_logs(path) - self.logger.debug("Services loaded") - else: - self.logger.warning("No services file found") - - def _get_service_code(self, services_lst: List[str], lineno: int) -> List[str]: - """Get service code from services list. - - Example: - >>> _get_service_code(["def is_upper_case(name):\n", " return name.isupper()"], 1) - ['def is_upper_case(name):\n', ' return name.isupper()'] - """ - service: List[str] = [] - func_lines: List[str] = services_lst[lineno - 1 :] - self.logger.debug("services_lst: %s", services_lst) - for func_lineno, func_line in enumerate(func_lines): - if func_line.startswith("def ") and func_lineno != 0: - break - service.append(func_line) # ?maybe with \n - return service - - async def load(self) -> None: - """Load index and services into memory.""" - if not self.path.exists(): - raise FileNotFoundError(f"File {self.path} doesn't exist") - - await asyncio.gather( - self._load_index(), - self._load_conditions(), - self._load_responses(), - self._load_services(), - ) - self.logger.info("Index and services loaded") - self.logger.debug("Loaded index: %s", self.index) - - def get_services(self) -> dict: - """Get indexed services. - - Example: - >>> get_services() - { - "is_upper_case": {"type": "condition", "lineno": 3}, - "say_hi": {"type": "response", "lineno": 5} - } - """ - return self.index - - async def search_service(self, service_name: str) -> Optional[List[str]]: - """Get the body code of a service based on its indexed info (type, lineno). - - Example: - >>> search_service("is_upper_case") - ["def is_upper_case(name):\n", " return name.isupper()"] - - """ - if service_name not in self.index: - return [] - service_type = self.index[service_name]["type"] - lineno = int(self.index[service_name]["lineno"]) - - if service_type == "condition": - return self._get_service_code(self.conditions, lineno) - elif service_type == "response": - return self._get_service_code(self.responses, lineno) - elif service_type == "service": - return self._get_service_code(self.services, lineno) - - async def indexit(self, service_name: str, type_: str, lineno: int) -> None: - """Add service info to the index using indexit_all method.""" - self.logger.debug("Indexing '%s'", service_name) - await self.indexit_all([service_name], [type_], [lineno]) - self.logger.info("Indexed '%s'", service_name) - - async def indexit_all(self, services_names: List[str], types: List[str], linenos: List[int]) -> None: - """Index multiple services. - - The index is added to the index in the form: {service_name: {"type": ``type_``, "lineno": lineno}}. - - Args: - services_names: list of service names - types: list of service types ("condition", "response", "service") - linenos: list of service starting line numbers according to its place in the file. - - Raises: - FileNotFoundError: if the index file doesn't exist - - Example: - >>> services_names = ["is_upper_case", "say_hi"] - >>> types = ["condition", "response"] - >>> linenos = [3, 5] - >>> await indexit_all(services_names, types, linenos) - { - "is_upper_case": {"type": "condition", "lineno": 3}, - "say_hi": {"type": "response", "lineno": 5} - } - - Returns: - None - """ - if not self.path.exists(): - raise FileNotFoundError(f"File {self.path} doesn't exist") - - for service_name, type_, lineno in zip(services_names, types, linenos): - self.index[service_name] = { - "type": type_, # condition/response/service - "lineno": lineno, - } - - await write_conf(self.index, self.path) # ?to background tasks diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index 4f601fc9..a884ba45 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -59,3 +59,13 @@ def store_custom_service(services_path: Path, services: List[str]): with open(services_path, "w") as file: file.write(ast.unparse(conditions_tree)) + + +def get_all_classes(services_path): + with open(services_path, "r", encoding="UTF-8") as file: + conditions_tree = ast.parse(file.read()) + + return [ + {"name": node.name, "body": ast.unparse(node)} + for node in conditions_tree.body if isinstance(node, ast.ClassDef) + ] diff --git a/backend/chatsky_ui/services/process_manager.py b/backend/chatsky_ui/services/process_manager.py index 3a6aeceb..38746cb9 100644 --- a/backend/chatsky_ui/services/process_manager.py +++ b/backend/chatsky_ui/services/process_manager.py @@ -186,15 +186,13 @@ async def start(self, preset: Preset) -> int: return self.last_id - async def check_status(self, id_, index, *args, **kwargs): + async def check_status(self, id_, *args, **kwargs): """Checks the build "id_" process status by calling the `periodically_check_status` method of the process. This updates the process status in the database every 2 seconds. - The index is refreshed after the build is done/failed. """ await self.processes[id_].periodically_check_status() - await index.load() async def get_build_info(self, id_: int, run_manager: RunManager) -> Optional[Dict[str, Any]]: """Returns metadata of a specific build process identified by its unique ID. diff --git a/docs/appref/chatsky_ui/services.rst b/docs/appref/chatsky_ui/services.rst index 3be7e826..7b3c0074 100644 --- a/docs/appref/chatsky_ui/services.rst +++ b/docs/appref/chatsky_ui/services.rst @@ -1,14 +1,6 @@ chatsky_ui.services package ==================== -chatsky_ui.services.index module -------------------------- - -.. automodule:: chatsky_ui.services.index - :members: - :undoc-members: - :show-inheritance: - chatsky_ui.services.json\_converter module ----------------------------------- From 39f97f662f5ec4c03f7bde0581441ead53e246c8 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 5 Nov 2024 23:28:34 +0800 Subject: [PATCH 11/41] chore: Update to the new template repo --- Makefile | 2 +- backend/chatsky_ui/cli.py | 3 ++- backend/chatsky_ui/tests/api/test_bot.py | 4 ++-- .../chatsky_ui/tests/integration/test_api_integration.py | 8 ++++---- backend/chatsky_ui/tests/services/test_process_manager.py | 2 +- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Makefile b/Makefile index 05b58031..62ec2158 100644 --- a/Makefile +++ b/Makefile @@ -153,7 +153,7 @@ init_proj: install_backend_env ## Initiates a new project using chatsky-ui .PHONY: init_with_cc init_with_cc: ## Initiates a new project using cookiecutter - cookiecutter https://github.com/Ramimashkouk/df_d_template.git + cookiecutter https://github.com/deeppavlov/chatsky-ui-template.git .PHONY: build_docs diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 2708f206..db77dd17 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -184,9 +184,10 @@ def init( try: os.chdir(destination) cookiecutter( - "https://github.com/Ramimashkouk/df_d_template.git", + "https://github.com/deeppavlov/chatsky-ui-template.git", no_input=no_input, overwrite_if_exists=overwrite_if_exists, + checkout="add-test" ) finally: os.chdir(original_dir) diff --git a/backend/chatsky_ui/tests/api/test_bot.py b/backend/chatsky_ui/tests/api/test_bot.py index f50529c4..f6b5c2b4 100644 --- a/backend/chatsky_ui/tests/api/test_bot.py +++ b/backend/chatsky_ui/tests/api/test_bot.py @@ -16,8 +16,8 @@ from chatsky_ui.services.process_manager import RunManager PROCESS_ID = 0 -RUN_ID = 42 -BUILD_ID = 43 +RUN_ID = 0 +BUILD_ID = 0 @pytest.mark.asyncio diff --git a/backend/chatsky_ui/tests/integration/test_api_integration.py b/backend/chatsky_ui/tests/integration/test_api_integration.py index 6ab9716a..d0485262 100644 --- a/backend/chatsky_ui/tests/integration/test_api_integration.py +++ b/backend/chatsky_ui/tests/integration/test_api_integration.py @@ -151,7 +151,7 @@ async def test_stop_build_bad_id(mocker): "end_status, process_status", [("failure", Status.FAILED), ("loop", Status.RUNNING), ("success", Status.ALIVE)] ) async def test_start_run(mocker, end_status, process_status): - build_id = 43 + build_id = 0 await _test_start_process( mocker, get_run_manager, @@ -164,7 +164,7 @@ async def test_start_run(mocker, end_status, process_status): @pytest.mark.asyncio async def test_stop_run(mocker): - build_id = 43 + build_id = 0 await _test_stop_process( mocker, get_run_manager, @@ -175,7 +175,7 @@ async def test_stop_run(mocker): @pytest.mark.asyncio async def test_stop_run_bad_id(mocker): - build_id = 43 + build_id = 0 await _test_stop_inexistent_process( mocker, get_run_manager, @@ -186,7 +186,7 @@ async def test_stop_run_bad_id(mocker): @pytest.mark.asyncio async def test_connect_to_ws(mocker): - build_id = 43 + build_id = 0 async with httpx.AsyncClient(transport=ASGIWebSocketTransport(app)) as client: async with override_dependency(mocker, get_run_manager) as process_manager: diff --git a/backend/chatsky_ui/tests/services/test_process_manager.py b/backend/chatsky_ui/tests/services/test_process_manager.py index 11799169..3215a307 100644 --- a/backend/chatsky_ui/tests/services/test_process_manager.py +++ b/backend/chatsky_ui/tests/services/test_process_manager.py @@ -4,7 +4,7 @@ from omegaconf import OmegaConf RUN_ID = 42 -BUILD_ID = 43 +BUILD_ID = 0 class TestRunManager: From c4374497b5acc86d10eab68ab4fd7f34d3c6cf9c Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 8 Nov 2024 12:48:25 +0800 Subject: [PATCH 12/41] chore: Add logging to show weather it's gonna build --- backend/chatsky_ui/cli.py | 5 +++++ backend/chatsky_ui/utils/git_cmd.py | 3 +++ 2 files changed, 8 insertions(+) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 69917e86..14505002 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -101,6 +101,8 @@ def build_scenario( # TODO: add custom_dir - maybe the same way like project_dir ): """Builds the bot with preset `success`""" + logger = get_logger(__name__) + if not project_dir.is_dir(): raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) @@ -120,6 +122,9 @@ def build_scenario( pipeline_converter( input_file=settings.frontend_flows_path, output_dir=settings.scripts_dir ) #TODO: rename to frontend_graph_path + logger.info("Graph is changed. Gonna build") + else: + logger.info("Graph isn't changed. Ain't gonna build") # Save the project anyway to keep a gradual number of builds save_built_script_to_git(build_id, bot_repo) diff --git a/backend/chatsky_ui/utils/git_cmd.py b/backend/chatsky_ui/utils/git_cmd.py index 91b6bb6e..0c708d8c 100644 --- a/backend/chatsky_ui/utils/git_cmd.py +++ b/backend/chatsky_ui/utils/git_cmd.py @@ -29,13 +29,16 @@ def save_frontend_graph_to_git(build_id: int, chatsky_ui_repo: Repo): tags = sorted(chatsky_ui_repo.tags, key=lambda t: t.commit.committed_datetime) if len(tags) < 2: + logger.debug("Only one tag found") is_changed = False else: current_tag = tags[-1] previous_tag = tags[-2] diff = chatsky_ui_repo.git.diff(previous_tag.commit, current_tag.commit) + logger.debug("Git diff: %s", diff) is_changed = bool(diff) + logger.debug("Is changed: %s", is_changed) return is_changed From 7433d3334b47017a82fb4e361bf4e535ebdb1539 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 8 Nov 2024 14:44:35 +0800 Subject: [PATCH 13/41] fix: Save tg_token in .env --- backend/chatsky_ui/api/api_v1/endpoints/flows.py | 11 +++++++++++ .../schemas/front_graph_components/interface.py | 8 +++++++- .../json_converter_new2/interface_converter.py | 6 +++++- backend/chatsky_ui/utils/git_cmd.py | 2 +- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/backend/chatsky_ui/api/api_v1/endpoints/flows.py b/backend/chatsky_ui/api/api_v1/endpoints/flows.py index 241df570..14ce6f7d 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/flows.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/flows.py @@ -9,6 +9,8 @@ from chatsky_ui.db.base import read_conf, write_conf from chatsky_ui.utils.git_cmd import commit_changes, get_repo from chatsky_ui.core.logger_config import get_logger +from pathlib import Path +from dotenv import set_key router = APIRouter() @@ -51,3 +53,12 @@ async def flows_post(flows: Dict[str, Union[list, dict]]) -> Dict[str, str]: commit_changes(repo, "Save frontend flows") return {"status": "ok"} + + +@router.post("/tg_token") +async def post_tg_token(token: str): + dotenv_path = Path(settings.work_directory) / ".env" + dotenv_path.touch(exist_ok=True) + + set_key(dotenv_path, "TG_BOT_TOKEN", token) + return {"status": "ok", "message": "Token saved successfully"} diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index c5bafbfb..eaa39419 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -3,6 +3,10 @@ from .base_component import BaseComponent from typing import Optional, Dict +from dotenv import load_dotenv +import os + +from chatsky_ui.core.config import settings class Interface(BaseComponent): telegram: Optional[Dict[str, Any]] = Field(default=None) @@ -17,6 +21,8 @@ def check_one_not_none(cls, values): @model_validator(mode='after') def check_telegram_token(cls, values): - if values.telegram is not None and 'token' not in values.telegram: + load_dotenv(os.path.join(settings.work_directory, '.env')) + tg_bot_token = os.getenv('TG_BOT_TOKEN') + if values.telegram is not None and not tg_bot_token: raise ValueError('Telegram token must be provided.') return values diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py index 42ba348a..4dbdce8d 100644 --- a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -10,5 +10,9 @@ def _convert(self): return {"chatsky.messengers.console.CLIMessengerInterface": {}} elif self.interface.telegram is not None: return { - "chatsky.messengers.telegram.LongpollingInterface": {"token": self.interface.telegram["token"]} + "chatsky.messengers.telegram.LongpollingInterface": { + "token": { + "external:os.getenv": "TG_BOT_TOKEN" + } + } } diff --git a/backend/chatsky_ui/utils/git_cmd.py b/backend/chatsky_ui/utils/git_cmd.py index 0c708d8c..5771ff6b 100644 --- a/backend/chatsky_ui/utils/git_cmd.py +++ b/backend/chatsky_ui/utils/git_cmd.py @@ -30,7 +30,7 @@ def save_frontend_graph_to_git(build_id: int, chatsky_ui_repo: Repo): tags = sorted(chatsky_ui_repo.tags, key=lambda t: t.commit.committed_datetime) if len(tags) < 2: logger.debug("Only one tag found") - is_changed = False + is_changed = True else: current_tag = tags[-1] previous_tag = tags[-2] From af4dab2b1550fccc5d94cb53dbf8e1c6016a0d6d Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 8 Nov 2024 16:39:14 +0800 Subject: [PATCH 14/41] feat: Support automatic transitions (previous, ...) --- backend/chatsky_ui/cli.py | 3 +-- .../json_converter_new2/node_converter.py | 15 ++++++++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 14505002..304836bc 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -101,11 +101,10 @@ def build_scenario( # TODO: add custom_dir - maybe the same way like project_dir ): """Builds the bot with preset `success`""" - logger = get_logger(__name__) - if not project_dir.is_dir(): raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) + logger = get_logger(__name__) bot_repo = get_repo(Path(project_dir) / "bot") chatsky_ui_repo = get_repo(settings.frontend_flows_path.parent) diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index 3fd0f4e1..73810477 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -23,6 +23,12 @@ def __init__(self, config: dict): class InfoNodeConverter(NodeConverter): + MAP_TR2CHATSKY = { + "start": "dst.Start", + "fallback": "dst.Fallback", + "previous": "dst.Previous", + "repeat": "dst.Current", + } def __init__(self, node: dict): self.node = InfoNode( id=node["id"], @@ -41,10 +47,13 @@ def _convert(self): RESPONSE: self.RESPONSE_CONVERTER[self.node.response["type"]](self.node.response)(), TRANSITIONS: [ { - "dst": condition["dst"], + "dst": condition["dst"] + if "dst" in condition and condition["data"]["transition_type"] == "manual" + else self.MAP_TR2CHATSKY[condition["data"]["transition_type"]], "priority": condition["data"]["priority"], - "cnd": converter(slots_conf=self.slots_conf) - } for condition, converter in zip(self.node.conditions, condition_converters) + "cnd": converter(slots_conf=self.slots_conf), + } + for condition, converter in zip(self.node.conditions, condition_converters) ], PRE_TRANSITION: { key: value From 42b8af1f03f0025dccd31d77ce4eb05bf85f7198 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 8 Nov 2024 16:39:29 +0800 Subject: [PATCH 15/41] style: Black up --- backend/chatsky_ui/cli.py | 19 ++++-- .../front_graph_components/base_component.py | 1 + .../info_holders/condition.py | 2 +- .../front_graph_components/interface.py | 13 ++-- .../schemas/front_graph_components/slot.py | 1 + .../json_converter_new2/base_converter.py | 1 + .../services/json_converter_new2/consts.py | 6 +- .../json_converter_new2/flow_converter.py | 12 ++-- .../interface_converter.py | 7 +-- .../condition_converter.py | 19 ++---- .../response_converter.py | 10 +-- .../service_replacer.py | 5 +- .../json_converter_new2/node_converter.py | 13 ++-- .../json_converter_new2/pipeline_converter.py | 1 + .../json_converter_new2/script_converter.py | 19 +++--- .../json_converter_new2/slots_converter.py | 18 +++--- backend/chatsky_ui/tests/unit/conftest.py | 63 +++++-------------- .../tests/unit/test_flow_converter.py | 26 ++------ .../tests/unit/test_logic_components.py | 47 +++++--------- .../tests/unit/test_node_converer.py | 31 ++------- .../tests/unit/test_slots_converter.py | 6 +- backend/chatsky_ui/utils/git_cmd.py | 2 +- 22 files changed, 121 insertions(+), 201 deletions(-) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 304836bc..3cc3827e 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -17,7 +17,12 @@ from chatsky_ui.core.config import app_runner, settings # noqa: E402 from chatsky_ui.core.logger_config import get_logger # noqa: E402 -from chatsky_ui.utils.git_cmd import commit_changes, get_repo, save_built_script_to_git, save_frontend_graph_to_git # noqa: E402 +from chatsky_ui.utils.git_cmd import ( + commit_changes, + get_repo, + save_built_script_to_git, + save_frontend_graph_to_git, +) # noqa: E402 cli = typer.Typer( help="🚀 Welcome to Chatsky-UI!\n\n" @@ -115,17 +120,19 @@ def build_scenario( is_changed = save_frontend_graph_to_git(build_id, chatsky_ui_repo) if is_changed: - from chatsky_ui.services.json_converter_new2.pipeline_converter import PipelineConverter # pylint: disable=C0415 + from chatsky_ui.services.json_converter_new2.pipeline_converter import ( + PipelineConverter, + ) # pylint: disable=C0415 pipeline_converter = PipelineConverter() pipeline_converter( input_file=settings.frontend_flows_path, output_dir=settings.scripts_dir - ) #TODO: rename to frontend_graph_path + ) # TODO: rename to frontend_graph_path logger.info("Graph is changed. Gonna build") else: logger.info("Graph isn't changed. Ain't gonna build") - - # Save the project anyway to keep a gradual number of builds + + # Save the project anyway to keep a gradual number of builds save_built_script_to_git(build_id, bot_repo) @@ -218,7 +225,7 @@ def init( "https://github.com/deeppavlov/chatsky-ui-template.git", no_input=no_input, overwrite_if_exists=overwrite_if_exists, - checkout="add-test" + checkout="add-test", ) finally: os.chdir(original_dir) diff --git a/backend/chatsky_ui/schemas/front_graph_components/base_component.py b/backend/chatsky_ui/schemas/front_graph_components/base_component.py index 6cf3aa88..4fd6aba2 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/base_component.py +++ b/backend/chatsky_ui/schemas/front_graph_components/base_component.py @@ -1,4 +1,5 @@ from pydantic import BaseModel + class BaseComponent(BaseModel): pass diff --git a/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py b/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py index 3789472f..199c4ee6 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py +++ b/backend/chatsky_ui/schemas/front_graph_components/info_holders/condition.py @@ -10,4 +10,4 @@ class CustomCondition(Condition): class SlotCondition(Condition): - slot_id: str # not the condition id + slot_id: str # not the condition id diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index eaa39419..e7d29ddc 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -8,21 +8,22 @@ from chatsky_ui.core.config import settings + class Interface(BaseComponent): telegram: Optional[Dict[str, Any]] = Field(default=None) cli: Optional[Dict[str, Any]] = Field(default=None) - @model_validator(mode='after') + @model_validator(mode="after") def check_one_not_none(cls, values): telegram, cli = values.telegram, values.cli if (telegram is None) == (cli is None): raise ValueError('Exactly one of "telegram" or "cli" must be provided.') return values - - @model_validator(mode='after') + + @model_validator(mode="after") def check_telegram_token(cls, values): - load_dotenv(os.path.join(settings.work_directory, '.env')) - tg_bot_token = os.getenv('TG_BOT_TOKEN') + load_dotenv(os.path.join(settings.work_directory, ".env")) + tg_bot_token = os.getenv("TG_BOT_TOKEN") if values.telegram is not None and not tg_bot_token: - raise ValueError('Telegram token must be provided.') + raise ValueError("Telegram token must be provided.") return values diff --git a/backend/chatsky_ui/schemas/front_graph_components/slot.py b/backend/chatsky_ui/schemas/front_graph_components/slot.py index 1ef338d1..b6d683e1 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/slot.py +++ b/backend/chatsky_ui/schemas/front_graph_components/slot.py @@ -2,6 +2,7 @@ from .base_component import BaseComponent + class Slot(BaseComponent): name: str diff --git a/backend/chatsky_ui/services/json_converter_new2/base_converter.py b/backend/chatsky_ui/services/json_converter_new2/base_converter.py index 6d654f12..aa5dff17 100644 --- a/backend/chatsky_ui/services/json_converter_new2/base_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/base_converter.py @@ -1,5 +1,6 @@ from abc import ABC, abstractmethod + class BaseConverter(ABC): def __call__(self, *args, **kwargs): return self._convert() diff --git a/backend/chatsky_ui/services/json_converter_new2/consts.py b/backend/chatsky_ui/services/json_converter_new2/consts.py index d0219028..388bc405 100644 --- a/backend/chatsky_ui/services/json_converter_new2/consts.py +++ b/backend/chatsky_ui/services/json_converter_new2/consts.py @@ -1,3 +1,3 @@ -RESPONSES_FILE="responses" -CONDITIONS_FILE="conditions" -CUSTOM_FILE="custom" +RESPONSES_FILE = "responses" +CONDITIONS_FILE = "conditions" +CUSTOM_FILE = "custom" diff --git a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py index 587033b9..9b314340 100644 --- a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py @@ -23,13 +23,15 @@ def __call__(self, *args, **kwargs): self.slots_conf = kwargs["slots_conf"] self._integrate_edges_into_nodes() return super().__call__(*args, **kwargs) - + def _validate_flow(self, flow: Dict[str, Any]): if "data" not in flow or "nodes" not in flow["data"] or "edges" not in flow["data"]: raise ValueError("Invalid flow structure") def _integrate_edges_into_nodes(self): - def _insert_dst_into_condition(node: Dict[str, Any], condition_id: str, target_node: Tuple[str, str]) -> Dict[str, Any]: + def _insert_dst_into_condition( + node: Dict[str, Any], condition_id: str, target_node: Tuple[str, str] + ) -> Dict[str, Any]: for condition in node["data"]["conditions"]: if condition["id"] == condition_id: condition["dst"] = target_node @@ -46,7 +48,7 @@ def _insert_dst_into_condition(node: Dict[str, Any], condition_id: str, target_n def _map_edges(self) -> List[Dict[str, Any]]: def _get_flow_and_node_names(target_node): node_type = target_node["type"] - if node_type == "link_node": #TODO: WHY CONVERTING HERE? + if node_type == "link_node": # TODO: WHY CONVERTING HERE? return LinkNodeConverter(target_node)(mapped_flows=self.mapped_flows) elif node_type == "default_node": return [self.flow.name, target_node["data"]["name"]] @@ -63,5 +65,7 @@ def _convert(self) -> Dict[str, Any]: converted_flow = {self.flow.name: {}} for node in self.flow.nodes: if node["type"] == "default_node": - converted_flow[self.flow.name].update({node["data"]["name"]: InfoNodeConverter(node)(slots_conf=self.slots_conf)}) + converted_flow[self.flow.name].update( + {node["data"]["name"]: InfoNodeConverter(node)(slots_conf=self.slots_conf)} + ) return converted_flow diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py index 4dbdce8d..a8d94821 100644 --- a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -1,6 +1,7 @@ from .base_converter import BaseConverter from ...schemas.front_graph_components.interface import Interface + class InterfaceConverter(BaseConverter): def __init__(self, interface: dict): self.interface = Interface(**interface) @@ -10,9 +11,5 @@ def _convert(self): return {"chatsky.messengers.console.CLIMessengerInterface": {}} elif self.interface.telegram is not None: return { - "chatsky.messengers.telegram.LongpollingInterface": { - "token": { - "external:os.getenv": "TG_BOT_TOKEN" - } - } + "chatsky.messengers.telegram.LongpollingInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} } diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py index 58a450d5..8cc22b31 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -31,11 +31,9 @@ def __init__(self, condition: dict): def _convert(self): store_custom_service(settings.conditions_path, [self.condition.code]) - custom_cnd = { - f"{CUSTOM_FILE}.{CONDITIONS_FILE}.{self.condition.name}": None - } + custom_cnd = {f"{CUSTOM_FILE}.{CONDITIONS_FILE}.{self.condition.name}": None} return custom_cnd - + def get_pre_transitions(self): return {} @@ -44,10 +42,7 @@ class SlotConditionConverter(ConditionConverter): def __init__(self, condition: dict): self.condition = None try: - self.condition = SlotCondition( - slot_id=condition["data"]["slot"], - name=condition["name"] - ) + self.condition = SlotCondition(slot_id=condition["data"]["slot"], name=condition["name"]) except KeyError as missing_key: raise BadConditionException("Missing key in slot condition data") from missing_key @@ -59,9 +54,5 @@ def _convert(self): return {"chatsky.conditions.slots.SlotsExtracted": self.slots_conf[self.condition.slot_id]} def get_pre_transitions(self): - slot_path = self.slots_conf[self.condition.slot_id] # type: ignore - return { - slot_path: { - "chatsky.processing.slots.Extract": slot_path - } - } + slot_path = self.slots_conf[self.condition.slot_id] # type: ignore + return {slot_path: {"chatsky.processing.slots.Extract": slot_path}} diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py index 03300db0..791d7ed3 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -26,11 +26,7 @@ def __init__(self, response: dict): raise BadResponseException("Missing key in custom condition data") from e def _convert(self): - return { - "chatsky.Message": { - "text": self.response.text - } - } + return {"chatsky.Message": {"text": self.response.text}} class CustomResponseConverter(ResponseConverter): @@ -45,6 +41,4 @@ def __init__(self, response: dict): def _convert(self): store_custom_service(settings.responses_path, [self.response.code]) - return { - f"{CUSTOM_FILE}.{RESPONSES_FILE}.{self.response.name}": None - } + return {f"{CUSTOM_FILE}.{RESPONSES_FILE}.{self.response.name}": None} diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index a884ba45..b80d03bd 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -53,7 +53,7 @@ def _append_new_services(self, node: ast.Module): def store_custom_service(services_path: Path, services: List[str]): with open(services_path, "r", encoding="UTF-8") as file: conditions_tree = ast.parse(file.read()) - + replacer = ServiceReplacer(services) replacer.visit(conditions_tree) @@ -67,5 +67,6 @@ def get_all_classes(services_path): return [ {"name": node.name, "body": ast.unparse(node)} - for node in conditions_tree.body if isinstance(node, ast.ClassDef) + for node in conditions_tree.body + if isinstance(node, ast.ClassDef) ] diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index 73810477..f163b117 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -29,6 +29,7 @@ class InfoNodeConverter(NodeConverter): "previous": "dst.Previous", "repeat": "dst.Current", } + def __init__(self, node: dict): self.node = InfoNode( id=node["id"], @@ -36,13 +37,15 @@ def __init__(self, node: dict): response=node["data"]["response"], conditions=node["data"]["conditions"], ) - + def __call__(self, *args, **kwargs): self.slots_conf = kwargs["slots_conf"] return super().__call__(*args, **kwargs) - + def _convert(self): - condition_converters = [self.CONDITION_CONVERTER[condition["type"]](condition) for condition in self.node.conditions] + condition_converters = [ + self.CONDITION_CONVERTER[condition["type"]](condition) for condition in self.node.conditions + ] return { RESPONSE: self.RESPONSE_CONVERTER[self.node.response["type"]](self.node.response)(), TRANSITIONS: [ @@ -59,7 +62,7 @@ def _convert(self): key: value for converter in condition_converters for key, value in converter.get_pre_transitions().items() - } + }, } @@ -85,7 +88,7 @@ def _convert(self): # class ConfNodeConverter(NodeConverter): # def __init__(self, config: dict): # super().__init__(config) - + # def _convert(self): # return { diff --git a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py index c3a401b6..ffec6644 100644 --- a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py @@ -1,5 +1,6 @@ from pathlib import Path import yaml + try: from yaml import CLoader as Loader, CDumper as Dumper except ImportError: diff --git a/backend/chatsky_ui/services/json_converter_new2/script_converter.py b/backend/chatsky_ui/services/json_converter_new2/script_converter.py index fb10a7fc..ac42c499 100644 --- a/backend/chatsky_ui/services/json_converter_new2/script_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/script_converter.py @@ -8,7 +8,7 @@ class ScriptConverter(BaseConverter): def __init__(self, flows: List[dict]): self.script = Script(flows=flows) - self.mapped_flows = self._map_flows() #TODO: think about storing this in a temp file + self.mapped_flows = self._map_flows() # TODO: think about storing this in a temp file def __call__(self, *args, **kwargs): self.slots_conf = kwargs["slots_conf"] @@ -18,10 +18,7 @@ def _convert(self): return { key: value for flow in self.script.flows - for key, value in FlowConverter(flow)( - mapped_flows=self.mapped_flows, - slots_conf=self.slots_conf - ).items() + for key, value in FlowConverter(flow)(mapped_flows=self.mapped_flows, slots_conf=self.slots_conf).items() } def _map_flows(self): @@ -32,13 +29,13 @@ def _map_flows(self): mapped_flows[flow["name"]][node["id"]] = node return mapped_flows - def extract_start_fallback_labels(self): #TODO: refactor this huge method + def extract_start_fallback_labels(self): # TODO: refactor this huge method start_label, fallback_label = None, None - + for flow in self.script.flows: for node in flow["data"]["nodes"]: flags = node["data"].get("flags", []) - + if "start" in flags: if start_label: raise ValueError("Multiple start nodes found") @@ -47,8 +44,8 @@ def extract_start_fallback_labels(self): #TODO: refactor this huge method if fallback_label: raise ValueError("Multiple fallback nodes found") fallback_label = [flow["name"], node["data"]["name"]] - + if start_label and fallback_label: return start_label, fallback_label - - return start_label, fallback_label#return None, None + + return start_label, fallback_label # return None, None diff --git a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py index fc3e38aa..561e2bab 100644 --- a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py @@ -4,15 +4,14 @@ from ...schemas.front_graph_components.slot import GroupSlot, RegexpSlot from ...schemas.front_graph_components.node import SlotsNode + class SlotsConverter(BaseConverter): def __init__(self, flows: List[dict]): def _get_slots_node(flows): - return next(iter([ - node - for flow in flows - for node in flow["data"]["nodes"] - if node["type"] == "slots_node" - ]), {"id": "999999", "data": {"groups": []}}) + return next( + iter([node for flow in flows for node in flow["data"]["nodes"] if node["type"] == "slots_node"]), + {"id": "999999", "data": {"groups": []}}, + ) slots_node = _get_slots_node(flows) self.slots_node = SlotsNode( @@ -28,11 +27,8 @@ def map_slots(self): return mapped_slots def _convert(self): - return { - key: value - for group in self.slots_node.groups - for key, value in GroupSlotConverter(group)().items() - } + return {key: value for group in self.slots_node.groups for key, value in GroupSlotConverter(group)().items()} + class RegexpSlotConverter(SlotsConverter): def __init__(self, slot: dict): diff --git a/backend/chatsky_ui/tests/unit/conftest.py b/backend/chatsky_ui/tests/unit/conftest.py index bce099a8..674b2ca3 100644 --- a/backend/chatsky_ui/tests/unit/conftest.py +++ b/backend/chatsky_ui/tests/unit/conftest.py @@ -13,7 +13,7 @@ def custom_condition(): "python": { "action": """class test_condition(BaseCondition):\n async def call(self, ctx: Context) -> bool:\n return True""" - } + }, }, "dst": "dst_test_node", } @@ -21,9 +21,7 @@ def custom_condition(): @pytest.fixture def converted_custom_condition(): - return { - "custom.conditions.test_condition": None - } + return {"custom.conditions.test_condition": None} @pytest.fixture @@ -38,22 +36,18 @@ def custom_response(): Context) -> Message:\n return Message('Hello')""" } } - ] + ], } @pytest.fixture def converted_custom_response(): - return { - "custom.responses.test_response": None - } + return {"custom.responses.test_response": None} @pytest.fixture def slots_conf(): - return { - "test_slot": "test_slot" - } + return {"test_slot": "test_slot"} # @pytest.fixture @@ -90,17 +84,12 @@ def converted_regexp_slot(): @pytest.fixture def group_slot(regexp_slot): - return { - "name": "group_slot", - "slots": [regexp_slot] - } + return {"name": "group_slot", "slots": [regexp_slot]} @pytest.fixture def converted_group_slot(converted_regexp_slot): - return { - "group_slot": converted_regexp_slot - } + return {"group_slot": converted_regexp_slot} @pytest.fixture @@ -111,11 +100,9 @@ def info_node(custom_response, custom_condition): "data": { "name": "test_node", "response": custom_response, - "conditions": [ - custom_condition - ], + "conditions": [custom_condition], "flags": ["start", "fallback"], - } + }, } @@ -126,38 +113,22 @@ def flow(info_node, group_slot): "data": { "nodes": [ info_node, - { - "type": "slots_node", - "id": "test_slots_node_id", - "data": { - "groups": [group_slot] - } - }, + {"type": "slots_node", "id": "test_slots_node_id", "data": {"groups": [group_slot]}}, ], - "edges": [ - { - "source": "1", - "sourceHandle": "1", - "target": "1" - } - ] - } + "edges": [{"source": "1", "sourceHandle": "1", "target": "1"}], + }, } @pytest.fixture def mapped_flow(info_node): - return { - "test_flow": { - "1": info_node - } - } + return {"test_flow": {"1": info_node}} @pytest.fixture def telegram_interface(): return { - "telegram": { - "token": "test_token", - } - } \ No newline at end of file + "telegram": { + "token": "test_token", + } + } diff --git a/backend/chatsky_ui/tests/unit/test_flow_converter.py b/backend/chatsky_ui/tests/unit/test_flow_converter.py index c47a015e..d81d5b26 100644 --- a/backend/chatsky_ui/tests/unit/test_flow_converter.py +++ b/backend/chatsky_ui/tests/unit/test_flow_converter.py @@ -8,20 +8,15 @@ from chatsky_ui.services.json_converter_new2.pipeline_converter import PipelineConverter - @pytest.fixture def chatsky_flow(): return { "test_flow": { "test_node": { - "RESPONSE": { - "custom.responses.test_response": None - }, + "RESPONSE": {"custom.responses.test_response": None}, "TRANSITIONS": [ { - "cnd": { - "custom.conditions.test_condition": None - }, + "cnd": {"custom.conditions.test_condition": None}, "dst": "dst_test_node", "priority": 1, } @@ -38,7 +33,6 @@ def test_flow_converter(self, flow, mapped_flow, slots_conf, chatsky_flow): assert converted_flow == chatsky_flow - def test_flow_converter_fail_no_nodes(self, flow, mapped_flow, slots_conf): del flow["data"]["nodes"] with pytest.raises(ValueError): @@ -85,6 +79,7 @@ def test_extract_start_fallback_labels_fail_multiple_labels(self, flow, slots_co with pytest.raises(ValueError): converter.extract_start_fallback_labels() + class TestInterfaceConverter: def test_interface_converter(self, telegram_interface): interface = telegram_interface @@ -98,19 +93,13 @@ def test_interface_converter(self, telegram_interface): } def test_interface_fail_no_token(self): - interface = { - "telegram": {} - } + interface = {"telegram": {}} with pytest.raises(ValueError): InterfaceConverter(interface)() - def test_interface_fail_multiple_interfaces(self, telegram_interface): - interface = { - **telegram_interface, - "cli": {} - } + interface = {**telegram_interface, "cli": {}} with pytest.raises(ValueError): InterfaceConverter(interface)() @@ -118,10 +107,7 @@ def test_interface_fail_multiple_interfaces(self, telegram_interface): class TestPipelineConverter: def test_pipeline_converter(self, flow, telegram_interface, converted_group_slot, chatsky_flow): - pipeline = { - "flows": [flow], - "interface": telegram_interface - } + pipeline = {"flows": [flow], "interface": telegram_interface} pipeline_path = Path(__file__).parent / "test_pipeline.yaml" with open(pipeline_path, "w") as file: yaml.dump(pipeline, file) diff --git a/backend/chatsky_ui/tests/unit/test_logic_components.py b/backend/chatsky_ui/tests/unit/test_logic_components.py index c6f53735..ac49b758 100644 --- a/backend/chatsky_ui/tests/unit/test_logic_components.py +++ b/backend/chatsky_ui/tests/unit/test_logic_components.py @@ -1,9 +1,13 @@ import pytest from chatsky_ui.services.json_converter_new2.logic_component_converter.condition_converter import ( - CustomConditionConverter, SlotConditionConverter, BadConditionException + CustomConditionConverter, + SlotConditionConverter, + BadConditionException, ) from chatsky_ui.services.json_converter_new2.logic_component_converter.response_converter import ( - TextResponseConverter, CustomResponseConverter, BadResponseException + TextResponseConverter, + CustomResponseConverter, + BadResponseException, ) from chatsky_ui.services.json_converter_new2.logic_component_converter.service_replacer import store_custom_service from pathlib import Path @@ -11,40 +15,27 @@ @pytest.fixture def slot_condition(): - return { - "name": "test_condition", - "data": { - "slot": "test_slot" - } - } + return {"name": "test_condition", "data": {"slot": "test_slot"}} + @pytest.fixture def text_response(): - return { - "name": "test_response", - "data": [ - { - "text": "test_text" - } - ] - } + return {"name": "test_response", "data": [{"text": "test_text"}]} class TestConditionConverter: def test_custom_condition_converter(self, custom_condition, converted_custom_condition): converted_cnd = CustomConditionConverter(custom_condition)() assert converted_cnd == converted_custom_condition - + def test_custom_condition_converter_fail(self, slot_condition): with pytest.raises(BadConditionException): CustomConditionConverter(slot_condition)() def test_slot_condition_converter(self, slot_condition, slots_conf): converted_cnd = SlotConditionConverter(slot_condition)(slots_conf=slots_conf) - assert converted_cnd == { - "chatsky.conditions.slots.SlotsExtracted": "test_slot" - } - + assert converted_cnd == {"chatsky.conditions.slots.SlotsExtracted": "test_slot"} + def test_slot_condition_converter_fail(self, custom_condition): with pytest.raises(BadConditionException): SlotConditionConverter(custom_condition)() @@ -52,22 +43,14 @@ def test_slot_condition_converter_fail(self, custom_condition): def test_slot_condition_converter_get_pre_transitions(self, slot_condition, slots_conf): converter = SlotConditionConverter(slot_condition) converter(slots_conf=slots_conf) - assert converter.get_pre_transitions() == { - "test_slot": { - "chatsky.processing.slots.Extract": "test_slot" - } - } + assert converter.get_pre_transitions() == {"test_slot": {"chatsky.processing.slots.Extract": "test_slot"}} class TestResponseConverter: def test_text_response_converter(self, text_response): converted_response = TextResponseConverter(text_response)() - assert converted_response == { - "chatsky.Message": { - "text": "test_text" - } - } - + assert converted_response == {"chatsky.Message": {"text": "test_text"}} + def test_text_response_converter_fail(self, custom_response): with pytest.raises(BadResponseException): TextResponseConverter(custom_response)() diff --git a/backend/chatsky_ui/tests/unit/test_node_converer.py b/backend/chatsky_ui/tests/unit/test_node_converer.py index 471d60c1..82911349 100644 --- a/backend/chatsky_ui/tests/unit/test_node_converer.py +++ b/backend/chatsky_ui/tests/unit/test_node_converer.py @@ -8,36 +8,17 @@ def test_info_node_converter(self, info_node, slots_conf, converted_custom_respo converted_node = InfoNodeConverter(info_node)(slots_conf=slots_conf) assert converted_node == { - "RESPONSE": converted_custom_response, - "TRANSITIONS": [ - { - "dst": "dst_test_node", - "priority": 1, - "cnd": converted_custom_condition - } - ], - "PRE_TRANSITION": {}, - } + "RESPONSE": converted_custom_response, + "TRANSITIONS": [{"dst": "dst_test_node", "priority": 1, "cnd": converted_custom_condition}], + "PRE_TRANSITION": {}, + } def test_link_node_converter(self): link_node = { "id": "test_link_node", - "data": { - "transition": { - "target_flow": "test_flow", - "target_node": "test_node_id" - } - } - } - mapped_flows = { - "test_flow": { - "test_node_id": { - "data": { - "name": "test_node" - } - } - } + "data": {"transition": {"target_flow": "test_flow", "target_node": "test_node_id"}}, } + mapped_flows = {"test_flow": {"test_node_id": {"data": {"name": "test_node"}}}} converted_node = LinkNodeConverter(link_node)(mapped_flows=mapped_flows) diff --git a/backend/chatsky_ui/tests/unit/test_slots_converter.py b/backend/chatsky_ui/tests/unit/test_slots_converter.py index 44df3dfd..3e54c2a1 100644 --- a/backend/chatsky_ui/tests/unit/test_slots_converter.py +++ b/backend/chatsky_ui/tests/unit/test_slots_converter.py @@ -1,4 +1,8 @@ -from chatsky_ui.services.json_converter_new2.slots_converter import SlotsConverter, RegexpSlotConverter, GroupSlotConverter +from chatsky_ui.services.json_converter_new2.slots_converter import ( + SlotsConverter, + RegexpSlotConverter, + GroupSlotConverter, +) class TestSlotsConverter: diff --git a/backend/chatsky_ui/utils/git_cmd.py b/backend/chatsky_ui/utils/git_cmd.py index 5771ff6b..5b12111b 100644 --- a/backend/chatsky_ui/utils/git_cmd.py +++ b/backend/chatsky_ui/utils/git_cmd.py @@ -37,7 +37,7 @@ def save_frontend_graph_to_git(build_id: int, chatsky_ui_repo: Repo): diff = chatsky_ui_repo.git.diff(previous_tag.commit, current_tag.commit) logger.debug("Git diff: %s", diff) is_changed = bool(diff) - + logger.debug("Is changed: %s", is_changed) return is_changed From be819349144fdd52e0dcab68da669bf78fba5442 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 8 Nov 2024 16:47:22 +0800 Subject: [PATCH 16/41] style: Flake8 up --- .../chatsky_ui/api/api_v1/endpoints/chatsky_services.py | 5 ++--- backend/chatsky_ui/api/api_v1/endpoints/flows.py | 1 - backend/chatsky_ui/api/deps.py | 1 - backend/chatsky_ui/cli.py | 5 ++--- backend/chatsky_ui/schemas/front_graph_components/slot.py | 2 +- .../logic_component_converter/condition_converter.py | 1 - .../logic_component_converter/response_converter.py | 2 -- .../services/json_converter_new2/node_converter.py | 2 -- .../services/json_converter_new2/pipeline_converter.py | 3 --- backend/chatsky_ui/tests/unit/conftest.py | 8 ++++---- backend/chatsky_ui/tests/unit/test_logic_components.py | 4 ++-- backend/chatsky_ui/tests/unit/test_node_converer.py | 2 -- 12 files changed, 11 insertions(+), 25 deletions(-) diff --git a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py index 8b21cd5f..42e55214 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py @@ -1,10 +1,9 @@ -import ast import re from io import StringIO -from typing import Dict, Optional, Union +from typing import Dict, Union import aiofiles -from fastapi import APIRouter, Depends +from fastapi import APIRouter from pylint.lint import Run, pylinter from pylint.reporters.text import TextReporter diff --git a/backend/chatsky_ui/api/api_v1/endpoints/flows.py b/backend/chatsky_ui/api/api_v1/endpoints/flows.py index 14ce6f7d..caddcb29 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/flows.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/flows.py @@ -2,7 +2,6 @@ from fastapi import APIRouter, status, HTTPException from omegaconf import OmegaConf -from git import Repo from git.exc import GitCommandError from chatsky_ui.core.config import settings diff --git a/backend/chatsky_ui/api/deps.py b/backend/chatsky_ui/api/deps.py index 276d9474..7fc6391e 100644 --- a/backend/chatsky_ui/api/deps.py +++ b/backend/chatsky_ui/api/deps.py @@ -1,4 +1,3 @@ -from chatsky_ui.core.config import settings from chatsky_ui.services.process_manager import BuildManager, RunManager from chatsky_ui.services.websocket_manager import WebSocketManager diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 3cc3827e..1c44e3a1 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -9,7 +9,6 @@ import typer from cookiecutter.main import cookiecutter from typing_extensions import Annotated -import yaml from git import Repo # Patch nest_asyncio before importing Chatsky @@ -17,7 +16,7 @@ from chatsky_ui.core.config import app_runner, settings # noqa: E402 from chatsky_ui.core.logger_config import get_logger # noqa: E402 -from chatsky_ui.utils.git_cmd import ( +from chatsky_ui.utils.git_cmd import ( # noqa: E402 commit_changes, get_repo, save_built_script_to_git, @@ -165,7 +164,7 @@ def run_scenario( if not project_dir.is_dir(): raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - script_path = settings.scripts_dir / f"build.yaml" + script_path = settings.scripts_dir / "build.yaml" command_to_run = f"python {project_dir}/app.py --script-path {script_path}" try: diff --git a/backend/chatsky_ui/schemas/front_graph_components/slot.py b/backend/chatsky_ui/schemas/front_graph_components/slot.py index b6d683e1..1695286b 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/slot.py +++ b/backend/chatsky_ui/schemas/front_graph_components/slot.py @@ -1,4 +1,4 @@ -from typing import Optional, List +from typing import List from .base_component import BaseComponent diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py index 8cc22b31..d85f2325 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -1,5 +1,4 @@ from abc import ABC, abstractmethod -import ast from ..consts import CUSTOM_FILE, CONDITIONS_FILE from ..base_converter import BaseConverter diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py index 791d7ed3..2de84a93 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -1,5 +1,3 @@ -import ast - from ..base_converter import BaseConverter from ....schemas.front_graph_components.info_holders.response import TextResponse, CustomResponse from ..consts import CUSTOM_FILE, RESPONSES_FILE diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index f163b117..f313a3a2 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -1,5 +1,3 @@ -from typing import List - from .base_converter import BaseConverter from ...schemas.front_graph_components.node import InfoNode, LinkNode from .logic_component_converter.response_converter import TextResponseConverter, CustomResponseConverter diff --git a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py index ffec6644..8efd3040 100644 --- a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py @@ -7,11 +7,8 @@ from yaml import Loader, Dumper from ...schemas.front_graph_components.pipeline import Pipeline -from ...schemas.front_graph_components.interface import Interface -from ...schemas.front_graph_components.flow import Flow from .base_converter import BaseConverter -from .flow_converter import FlowConverter from .script_converter import ScriptConverter from .interface_converter import InterfaceConverter from .slots_converter import SlotsConverter diff --git a/backend/chatsky_ui/tests/unit/conftest.py b/backend/chatsky_ui/tests/unit/conftest.py index 674b2ca3..1ca98566 100644 --- a/backend/chatsky_ui/tests/unit/conftest.py +++ b/backend/chatsky_ui/tests/unit/conftest.py @@ -11,8 +11,8 @@ def custom_condition(): "priority": 1, "transition_type": "manual", "python": { - "action": """class test_condition(BaseCondition):\n async def call(self, ctx: - Context) -> bool:\n return True""" + "action": """class test_condition(BaseCondition):\n async def call(self, ctx: + Context) -> bool:\n return True""" }, }, "dst": "dst_test_node", @@ -32,8 +32,8 @@ def custom_response(): "data": [ { "python": { - "action": """class test_response(BaseResponse):\n async def call(self, ctx: - Context) -> Message:\n return Message('Hello')""" + "action": """class test_response(BaseResponse):\n async def call(self, ctx: + Context) -> Message:\n return Message('Hello')""" } } ], diff --git a/backend/chatsky_ui/tests/unit/test_logic_components.py b/backend/chatsky_ui/tests/unit/test_logic_components.py index ac49b758..b102b0fa 100644 --- a/backend/chatsky_ui/tests/unit/test_logic_components.py +++ b/backend/chatsky_ui/tests/unit/test_logic_components.py @@ -66,8 +66,8 @@ def test_custom_response_converter_fail(self, text_response): def test_store_custom_service(): current_file_path = Path(__file__).resolve() - service_code = """class test_service(BaseService):\n async def call(self, ctx: - Context) -> Message:\n return Message('Hello')""" + service_code = """class test_service(BaseService):\n async def call(self, ctx: + Context) -> Message:\n return Message('Hello')""" test_file_path = current_file_path.parent / "store_service_test.py" test_file_path.touch(exist_ok=True) diff --git a/backend/chatsky_ui/tests/unit/test_node_converer.py b/backend/chatsky_ui/tests/unit/test_node_converer.py index 82911349..45260db9 100644 --- a/backend/chatsky_ui/tests/unit/test_node_converer.py +++ b/backend/chatsky_ui/tests/unit/test_node_converer.py @@ -1,5 +1,3 @@ -import pytest - from chatsky_ui.services.json_converter_new2.node_converter import InfoNodeConverter, LinkNodeConverter From 30f38c6d566bb64028f761512bb9121dabb0ede8 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Thu, 14 Nov 2024 22:53:07 +0800 Subject: [PATCH 17/41] fix: Check for unique group names --- backend/chatsky_ui/schemas/front_graph_components/node.py | 8 ++++++++ .../logic_component_converter/service_replacer.py | 1 + 2 files changed, 9 insertions(+) diff --git a/backend/chatsky_ui/schemas/front_graph_components/node.py b/backend/chatsky_ui/schemas/front_graph_components/node.py index c47e6198..4911333c 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/node.py +++ b/backend/chatsky_ui/schemas/front_graph_components/node.py @@ -1,4 +1,5 @@ from typing import List +from pydantic import model_validator from .base_component import BaseComponent @@ -20,3 +21,10 @@ class LinkNode(Node): class SlotsNode(Node): groups: List[dict] + + @model_validator(mode="after") + def check_unique_groups_names(cls, values) -> 'SlotsNode': + groups_names = [group["name"] for group in values.groups] + if len(groups_names) != len(set(groups_names)): + raise ValueError(f"Slot groups names should be unique. Got duplicates: {groups_names}") + return values diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index b80d03bd..2253fd2d 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -36,6 +36,7 @@ def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: def _get_class_def(self, node: ast.ClassDef) -> ast.ClassDef: service = self.new_services_classes[node.name] del self.new_services_classes[node.name] + logger.info("Updating class '%s'", node.name) return service def generic_visit(self, node: ast.AST): From 463a7460f7302255daf6355d9b268826feecac08 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Thu, 14 Nov 2024 22:54:44 +0800 Subject: [PATCH 18/41] feat: Integrate slots in responses by FillTemplate --- .../chatsky_ui/services/json_converter_new2/node_converter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index f313a3a2..fbdc2b84 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -3,7 +3,7 @@ from .logic_component_converter.response_converter import TextResponseConverter, CustomResponseConverter from .logic_component_converter.condition_converter import CustomConditionConverter, SlotConditionConverter -from chatsky import RESPONSE, TRANSITIONS, PRE_TRANSITION +from chatsky import RESPONSE, TRANSITIONS, PRE_TRANSITION, PRE_RESPONSE class NodeConverter(BaseConverter): @@ -61,6 +61,7 @@ def _convert(self): for converter in condition_converters for key, value in converter.get_pre_transitions().items() }, + PRE_RESPONSE: {"fill": {"chatsky.processing.FillTemplate": None}}, } From 53ea889639c967a28d435f3d3e149d885eb07293 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 19 Nov 2024 14:13:03 +0800 Subject: [PATCH 19/41] feat: Delete websocket and use http_interface --- .../chatsky_ui/api/api_v1/endpoints/bot.py | 64 +-- backend/chatsky_ui/api/deps.py | 10 +- .../front_graph_components/interface.py | 8 +- .../interface_converter.py | 6 +- .../chatsky_ui/services/websocket_manager.py | 80 ---- backend/poetry.lock | 393 +----------------- backend/pyproject.toml | 4 +- 7 files changed, 42 insertions(+), 523 deletions(-) delete mode 100644 backend/chatsky_ui/services/websocket_manager.py diff --git a/backend/chatsky_ui/api/api_v1/endpoints/bot.py b/backend/chatsky_ui/api/api_v1/endpoints/bot.py index 6f0df7ee..d9cc003d 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/bot.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/bot.py @@ -2,13 +2,14 @@ from typing import Any, Dict, List, Optional, Union from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, WebSocket, WebSocketException, status +from chatsky.messengers.http_interface import HTTP_INTERFACE_PORT from chatsky_ui.api import deps from chatsky_ui.schemas.pagination import Pagination from chatsky_ui.schemas.preset import Preset from chatsky_ui.schemas.process_status import Status from chatsky_ui.services.process_manager import BuildManager, ProcessManager, RunManager -from chatsky_ui.services.websocket_manager import WebSocketManager +from httpx import AsyncClient router = APIRouter() @@ -234,47 +235,20 @@ async def get_run_logs( return await run_manager.fetch_run_logs(run_id, pagination.offset(), pagination.limit) -@router.websocket("/run/connect") -async def connect( - websocket: WebSocket, - websocket_manager: WebSocketManager = Depends(deps.get_websocket_manager), - run_manager: RunManager = Depends(deps.get_run_manager), -) -> None: - """Establishes a WebSocket connection to communicate with an alive run process identified by its 'run_id'. - - The WebSocket URL should adhere to the format: /bot/run/connect?run_id=. - """ - - run_manager.logger.debug("Connecting to websocket") - run_id = websocket.query_params.get("run_id") - - # Validate run_id - if run_id is None: - run_manager.logger.error("No run_id provided") - raise WebSocketException(code=status.WS_1008_POLICY_VIOLATION) - if not run_id.isdigit(): - run_manager.logger.error("A non-digit run run_id provided") - raise WebSocketException(code=status.WS_1003_UNSUPPORTED_DATA) - run_id = int(run_id) - if run_id not in run_manager.processes: - run_manager.logger.error("process with run_id '%s' exited or never existed", run_id) - raise WebSocketException(code=status.WS_1014_BAD_GATEWAY) - - await websocket_manager.connect(websocket) - run_manager.logger.info("Websocket for run process '%s' has been opened", run_id) - - output_task = asyncio.create_task( - websocket_manager.send_process_output_to_websocket(run_id, run_manager, websocket) - ) - input_task = asyncio.create_task( - websocket_manager.forward_websocket_messages_to_process(run_id, run_manager, websocket) - ) - - # Wait for either task to finish - _, websocket_manager.pending_tasks[websocket] = await asyncio.wait( - [output_task, input_task], - return_when=asyncio.FIRST_COMPLETED, - ) - websocket_manager.disconnect(websocket) - if await run_manager.get_status(run_id) in [Status.ALIVE, Status.RUNNING]: - await run_manager.stop(run_id) +@router.post("/chat", status_code=201) +async def respond( + user_id: str, + user_message: str, +): + async with AsyncClient() as client: + try: + response = await client.post( + f"http://localhost:{HTTP_INTERFACE_PORT}/chat", + params={"user_id": user_id, "user_message": user_message}, + ) + return response.json() + except Exception as e: + raise HTTPException( + status_code=status.HTTP_503_SERVICE_UNAVAILABLE, + detail=f"Please check that service's up and running on the port '{HTTP_INTERFACE_PORT}' that you're trying to reach.", + ) from e diff --git a/backend/chatsky_ui/api/deps.py b/backend/chatsky_ui/api/deps.py index 7fc6391e..af10d17f 100644 --- a/backend/chatsky_ui/api/deps.py +++ b/backend/chatsky_ui/api/deps.py @@ -1,5 +1,5 @@ from chatsky_ui.services.process_manager import BuildManager, RunManager -from chatsky_ui.services.websocket_manager import WebSocketManager + build_manager = BuildManager() @@ -15,11 +15,3 @@ def get_build_manager() -> BuildManager: def get_run_manager() -> RunManager: run_manager.set_logger() return run_manager - - -websocket_manager = WebSocketManager() - - -def get_websocket_manager() -> WebSocketManager: - websocket_manager.set_logger() - return websocket_manager diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index e7d29ddc..5d6cc25c 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -11,13 +11,13 @@ class Interface(BaseComponent): telegram: Optional[Dict[str, Any]] = Field(default=None) - cli: Optional[Dict[str, Any]] = Field(default=None) + http: Optional[Dict[str, Any]] = Field(default=None) @model_validator(mode="after") def check_one_not_none(cls, values): - telegram, cli = values.telegram, values.cli - if (telegram is None) == (cli is None): - raise ValueError('Exactly one of "telegram" or "cli" must be provided.') + non_none_values = [x for x in [values.telegram, values.http] if x is not None] + if len(non_none_values) != 1: + raise ValueError('Exactly one of "telegram", or "http" must be provided.') return values @model_validator(mode="after") diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py index a8d94821..c5df1e3b 100644 --- a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -7,9 +7,9 @@ def __init__(self, interface: dict): self.interface = Interface(**interface) def _convert(self): - if self.interface.cli is not None: - return {"chatsky.messengers.console.CLIMessengerInterface": {}} + if self.interface.http is not None: + return {"chatsky.messengers.HTTPMessengerInterface": {}} elif self.interface.telegram is not None: return { - "chatsky.messengers.telegram.LongpollingInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} + "chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} } diff --git a/backend/chatsky_ui/services/websocket_manager.py b/backend/chatsky_ui/services/websocket_manager.py deleted file mode 100644 index 70b57b8c..00000000 --- a/backend/chatsky_ui/services/websocket_manager.py +++ /dev/null @@ -1,80 +0,0 @@ -""" -Websocket class for controling websocket operations. -""" -import asyncio -from asyncio.tasks import Task -from typing import Dict, List, Set - -from fastapi import WebSocket, WebSocketDisconnect - -from chatsky_ui.core.logger_config import get_logger -from chatsky_ui.services.process_manager import ProcessManager - - -class WebSocketManager: - """Controls websocket operations connect, disconnect, check status, and communicate.""" - - def __init__(self): - self.pending_tasks: Dict[WebSocket, Set[Task]] = dict() - self.active_connections: List[WebSocket] = [] - self._logger = None - - @property - def logger(self): - if self._logger is None: - raise ValueError("Logger has not been configured. Call set_logger() first.") - return self._logger - - def set_logger(self): - self._logger = get_logger(__name__) - - async def connect(self, websocket: WebSocket): - """Accepts the websocket connection and marks it as active connection.""" - await websocket.accept() - self.active_connections.append(websocket) - - def disconnect(self, websocket: WebSocket): - """Cancels pending tasks of the open websocket process and removes it from active connections.""" - # TODO: await websocket.close() - if websocket in self.pending_tasks: - self.logger.info("Cancelling pending tasks") - for task in self.pending_tasks[websocket]: - task.cancel() - del self.pending_tasks[websocket] - self.active_connections.remove(websocket) - - def check_status(self, websocket: WebSocket): - if websocket in self.active_connections: - return websocket # return Status! - - async def send_process_output_to_websocket( - self, run_id: int, process_manager: ProcessManager, websocket: WebSocket - ): - """Reads and forwards process output to the websocket client.""" - try: - while True: - response = await process_manager.processes[run_id].read_stdout() - if not response: - break - await websocket.send_text(response.decode().strip().split("text=")[-1].strip("'")) - except WebSocketDisconnect: - self.logger.info("Websocket connection is closed by client") - except RuntimeError: - raise - - async def forward_websocket_messages_to_process( - self, run_id: int, process_manager: ProcessManager, websocket: WebSocket - ): - """Listens for messages from the websocket and sends them to the process.""" - try: - while True: - user_message = await websocket.receive_text() - if not user_message: - break - await process_manager.processes[run_id].write_stdin(user_message.encode() + b"\n") - except asyncio.CancelledError: - self.logger.info("Websocket connection is closed") - except WebSocketDisconnect: - self.logger.info("Websocket connection is closed by client") - except RuntimeError: - raise diff --git a/backend/poetry.lock b/backend/poetry.lock index 3df166f2..5e6d4efe 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -11,17 +11,6 @@ files = [ {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, ] -[[package]] -name = "aiolimiter" -version = "1.1.0" -description = "asyncio rate limiter, a leaky bucket implementation" -optional = false -python-versions = ">=3.7,<4.0" -files = [ - {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, - {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, -] - [[package]] name = "alabaster" version = "0.7.13" @@ -44,9 +33,6 @@ files = [ {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.9\""} - [[package]] name = "antlr4-python3-runtime" version = "4.9.3" @@ -79,34 +65,6 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin 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 = "apscheduler" -version = "3.10.4" -description = "In-process task scheduler with Cron-like capabilities" -optional = false -python-versions = ">=3.6" -files = [ - {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, - {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, -] - -[package.dependencies] -pytz = "*" -six = ">=1.4.0" -tzlocal = ">=2.0,<3.dev0 || >=4.dev0" - -[package.extras] -doc = ["sphinx", "sphinx-rtd-theme"] -gevent = ["gevent"] -mongodb = ["pymongo (>=3.0)"] -redis = ["redis (>=3.0)"] -rethinkdb = ["rethinkdb (>=2.4.0)"] -sqlalchemy = ["sqlalchemy (>=1.4)"] -testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] -tornado = ["tornado (>=4.3)"] -twisted = ["twisted"] -zookeeper = ["kazoo"] - [[package]] name = "arrow" version = "1.3.0" @@ -151,40 +109,9 @@ files = [ {file = "babel-2.15.0.tar.gz", hash = "sha256:8daf0e265d05768bc6c7a314cf1321e9a123afc328cc635c18622a2f30a04413"}, ] -[package.dependencies] -pytz = {version = ">=2015.7", markers = "python_version < \"3.9\""} - [package.extras] dev = ["freezegun (>=1.0,<2.0)", "pytest (>=6.0)", "pytest-cov"] -[[package]] -name = "backports-zoneinfo" -version = "0.2.1" -description = "Backport of the standard library zoneinfo module" -optional = false -python-versions = ">=3.6" -files = [ - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-macosx_10_14_x86_64.whl", hash = "sha256:da6013fd84a690242c310d77ddb8441a559e9cb3d3d59ebac9aca1a57b2e18bc"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:89a48c0d158a3cc3f654da4c2de1ceba85263fafb861b98b59040a5086259722"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-manylinux1_x86_64.whl", hash = "sha256:1c5742112073a563c81f786e77514969acb58649bcdf6cdf0b4ed31a348d4546"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win32.whl", hash = "sha256:e8236383a20872c0cdf5a62b554b27538db7fa1bbec52429d8d106effbaeca08"}, - {file = "backports.zoneinfo-0.2.1-cp36-cp36m-win_amd64.whl", hash = "sha256:8439c030a11780786a2002261569bdf362264f605dfa4d65090b64b05c9f79a7"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-macosx_10_14_x86_64.whl", hash = "sha256:f04e857b59d9d1ccc39ce2da1021d196e47234873820cbeaad210724b1ee28ac"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:17746bd546106fa389c51dbea67c8b7c8f0d14b5526a579ca6ccf5ed72c526cf"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-manylinux1_x86_64.whl", hash = "sha256:5c144945a7752ca544b4b78c8c41544cdfaf9786f25fe5ffb10e838e19a27570"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win32.whl", hash = "sha256:e55b384612d93be96506932a786bbcde5a2db7a9e6a4bb4bffe8b733f5b9036b"}, - {file = "backports.zoneinfo-0.2.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a76b38c52400b762e48131494ba26be363491ac4f9a04c1b7e92483d169f6582"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-macosx_10_14_x86_64.whl", hash = "sha256:8961c0f32cd0336fb8e8ead11a1f8cd99ec07145ec2931122faaac1c8f7fd987"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e81b76cace8eda1fca50e345242ba977f9be6ae3945af8d46326d776b4cf78d1"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-manylinux1_x86_64.whl", hash = "sha256:7b0a64cda4145548fed9efc10322770f929b944ce5cee6c0dfe0c87bf4c0c8c9"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win32.whl", hash = "sha256:1b13e654a55cd45672cb54ed12148cd33628f672548f373963b0bff67b217328"}, - {file = "backports.zoneinfo-0.2.1-cp38-cp38-win_amd64.whl", hash = "sha256:4a0f800587060bf8880f954dbef70de6c11bbe59c673c3d818921f042f9954a6"}, - {file = "backports.zoneinfo-0.2.1.tar.gz", hash = "sha256:fadbfe37f74051d024037f223b8e001611eac868b5c5b06144ef4d8b799862f2"}, -] - -[package.extras] -tzdata = ["tzdata"] - [[package]] name = "binaryornot" version = "0.4.4" @@ -234,17 +161,6 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] -[[package]] -name = "cachetools" -version = "5.5.0" -description = "Extensible memoizing collections and decorators" -optional = false -python-versions = ">=3.7" -files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, -] - [[package]] name = "certifi" version = "2024.2.2" @@ -256,85 +172,6 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] -[[package]] -name = "cffi" -version = "1.17.1" -description = "Foreign Function Interface for Python calling C code." -optional = false -python-versions = ">=3.8" -files = [ - {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, - {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, - {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, - {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, - {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, - {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, - {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, - {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, - {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, - {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, - {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, - {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, - {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, - {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, - {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, - {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, - {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, - {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, - {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, - {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, - {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, - {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, - {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, - {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, - {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, - {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, - {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, - {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, - {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, - {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, - {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, -] - -[package.dependencies] -pycparser = "*" - [[package]] name = "chardet" version = "5.2.0" @@ -447,22 +284,18 @@ files = [ [[package]] name = "chatsky" -version = "1.0.0rc1" +version = "0.9.0" description = "Chatsky is a free and open-source software stack for creating chatbots, released under the terms of Apache License 2.0." optional = false -python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,>=3.8" -files = [ - {file = "chatsky-1.0.0rc1-py3-none-any.whl", hash = "sha256:cd2ab29aa814d1719d68ad8e2245ced165fa3959143b50e4e4347a0cc9887339"}, - {file = "chatsky-1.0.0rc1.tar.gz", hash = "sha256:e6f19886b5d33c2a3f7f96f06f1965ebec875179683fcdda5ca90e1323973a23"}, -] +python-versions = "^3.9,!=3.9.7" +files = [] +develop = false [package.dependencies] colorama = "*" eval_type_backport = "*" nest-asyncio = "*" pydantic = ">=2.0" -python-telegram-bot = {version = ">=21.3,<22.0", extras = ["all"], optional = true, markers = "extra == \"telegram\""} -pyyaml = {version = "*", optional = true, markers = "extra == \"yaml\""} typing-extensions = "*" wrapt = "*" @@ -477,9 +310,16 @@ redis = ["redis"] sqlite = ["aiosqlite", "sqlalchemy[asyncio]"] stats = ["omegaconf", "opentelemetry-exporter-otlp (>=1.20.0)", "opentelemetry-instrumentation", "requests", "tqdm"] telegram = ["python-telegram-bot[all] (>=21.3,<22.0)"] +web-api = ["fastapi", "uvicorn"] yaml = ["pyyaml"] ydb = ["six", "ydb"] +[package.source] +type = "git" +url = "https://github.com/deeppavlov/chatsky.git" +reference = "feat/add-docker-image" +resolved_reference = "d4296f00b9369f6e4f9119c7cde5fe7ac71c32f9" + [[package]] name = "click" version = "8.1.7" @@ -613,55 +453,6 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] -[[package]] -name = "cryptography" -version = "43.0.1" -description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." -optional = false -python-versions = ">=3.7" -files = [ - {file = "cryptography-43.0.1-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:8385d98f6a3bf8bb2d65a73e17ed87a3ba84f6991c155691c51112075f9ffc5d"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27e613d7077ac613e399270253259d9d53872aaf657471473ebfc9a52935c062"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68aaecc4178e90719e95298515979814bda0cbada1256a4485414860bd7ab962"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:de41fd81a41e53267cb020bb3a7212861da53a7d39f863585d13ea11049cf277"}, - {file = "cryptography-43.0.1-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f98bf604c82c416bc829e490c700ca1553eafdf2912a91e23a79d97d9801372a"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:61ec41068b7b74268fa86e3e9e12b9f0c21fcf65434571dbb13d954bceb08042"}, - {file = "cryptography-43.0.1-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:014f58110f53237ace6a408b5beb6c427b64e084eb451ef25a28308270086494"}, - {file = "cryptography-43.0.1-cp37-abi3-win32.whl", hash = "sha256:2bd51274dcd59f09dd952afb696bf9c61a7a49dfc764c04dd33ef7a6b502a1e2"}, - {file = "cryptography-43.0.1-cp37-abi3-win_amd64.whl", hash = "sha256:666ae11966643886c2987b3b721899d250855718d6d9ce41b521252a17985f4d"}, - {file = "cryptography-43.0.1-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:ac119bb76b9faa00f48128b7f5679e1d8d437365c5d26f1c2c3f0da4ce1b553d"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bbcce1a551e262dfbafb6e6252f1ae36a248e615ca44ba302df077a846a8806"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58d4e9129985185a06d849aa6df265bdd5a74ca6e1b736a77959b498e0505b85"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:d03a475165f3134f773d1388aeb19c2d25ba88b6a9733c5c590b9ff7bbfa2e0c"}, - {file = "cryptography-43.0.1-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:511f4273808ab590912a93ddb4e3914dfd8a388fed883361b02dea3791f292e1"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:80eda8b3e173f0f247f711eef62be51b599b5d425c429b5d4ca6a05e9e856baa"}, - {file = "cryptography-43.0.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:38926c50cff6f533f8a2dae3d7f19541432610d114a70808f0926d5aaa7121e4"}, - {file = "cryptography-43.0.1-cp39-abi3-win32.whl", hash = "sha256:a575913fb06e05e6b4b814d7f7468c2c660e8bb16d8d5a1faf9b33ccc569dd47"}, - {file = "cryptography-43.0.1-cp39-abi3-win_amd64.whl", hash = "sha256:d75601ad10b059ec832e78823b348bfa1a59f6b8d545db3a24fd44362a1564cb"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:ea25acb556320250756e53f9e20a4177515f012c9eaea17eb7587a8c4d8ae034"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c1332724be35d23a854994ff0b66530119500b6053d0bd3363265f7e5e77288d"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:fba1007b3ef89946dbbb515aeeb41e30203b004f0b4b00e5e16078b518563289"}, - {file = "cryptography-43.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5b43d1ea6b378b54a1dc99dd8a2b5be47658fe9a7ce0a58ff0b55f4b43ef2b84"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:88cce104c36870d70c49c7c8fd22885875d950d9ee6ab54df2745f83ba0dc365"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:9d3cdb25fa98afdd3d0892d132b8d7139e2c087da1712041f6b762e4f807cc96"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e710bf40870f4db63c3d7d929aa9e09e4e7ee219e703f949ec4073b4294f6172"}, - {file = "cryptography-43.0.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:7c05650fe8023c5ed0d46793d4b7d7e6cd9c04e68eabe5b0aeea836e37bdcec2"}, - {file = "cryptography-43.0.1.tar.gz", hash = "sha256:203e92a75716d8cfb491dc47c79e17d0d9207ccffcbcb35f598fbe463ae3444d"}, -] - -[package.dependencies] -cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} - -[package.extras] -docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] -nox = ["nox"] -pep8test = ["check-sdist", "click", "mypy", "ruff"] -sdist = ["build"] -ssh = ["bcrypt (>=3.1.5)"] -test = ["certifi", "cryptography-vectors (==43.0.1)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] -test-randomorder = ["pytest-randomly"] - [[package]] name = "dill" version = "0.3.8" @@ -794,32 +585,6 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] -[[package]] -name = "h2" -version = "4.1.0" -description = "HTTP/2 State-Machine based protocol implementation" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, - {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, -] - -[package.dependencies] -hpack = ">=4.0,<5" -hyperframe = ">=6.0,<7" - -[[package]] -name = "hpack" -version = "4.0.0" -description = "Pure-Python HPACK header compression" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, - {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, -] - [[package]] name = "httpcore" version = "1.0.5" @@ -903,11 +668,9 @@ files = [ [package.dependencies] anyio = "*" certifi = "*" -h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} httpcore = "==1.*" idna = "*" sniffio = "*" -socksio = {version = "==1.*", optional = true, markers = "extra == \"socks\""} [package.extras] brotli = ["brotli", "brotlicffi"] @@ -932,17 +695,6 @@ httpcore = ">=1.0.4" httpx = ">=0.23.1" wsproto = "*" -[[package]] -name = "hyperframe" -version = "6.0.1" -description = "HTTP/2 framing layer for Python" -optional = false -python-versions = ">=3.6.1" -files = [ - {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, - {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, -] - [[package]] name = "idna" version = "3.7" @@ -1241,17 +993,6 @@ files = [ {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] -[[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.0" @@ -1557,53 +1298,6 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] -[[package]] -name = "python-telegram-bot" -version = "21.5" -description = "We have made you a wrapper you can't refuse" -optional = false -python-versions = ">=3.8" -files = [ - {file = "python_telegram_bot-21.5-py3-none-any.whl", hash = "sha256:1bbba653477ba164411622b717a0cfe1eb7843da016348e41df97f96c93f578e"}, - {file = "python_telegram_bot-21.5.tar.gz", hash = "sha256:2d679173072cce8d6b49aac2e438d49dbfc01c1a4ef5658828c2a65951ee830b"}, -] - -[package.dependencies] -aiolimiter = {version = ">=1.1.0,<1.2.0", optional = true, markers = "extra == \"all\""} -apscheduler = {version = ">=3.10.4,<3.11.0", optional = true, markers = "extra == \"all\""} -cachetools = {version = ">=5.3.3,<5.6.0", optional = true, markers = "extra == \"all\""} -cffi = {version = ">=1.17.0rc1", optional = true, markers = "python_version > \"3.12\" and extra == \"all\""} -cryptography = {version = ">=39.0.1", optional = true, markers = "extra == \"all\""} -httpx = [ - {version = ">=0.27,<1.0"}, - {version = "*", extras = ["http2"], optional = true, markers = "extra == \"all\""}, - {version = "*", extras = ["socks"], optional = true, markers = "extra == \"all\""}, -] -pytz = {version = ">=2018.6", optional = true, markers = "extra == \"all\""} -tornado = {version = ">=6.4,<7.0", optional = true, markers = "extra == \"all\""} - -[package.extras] -all = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] -callback-data = ["cachetools (>=5.3.3,<5.6.0)"] -ext = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] -http2 = ["httpx[http2]"] -job-queue = ["apscheduler (>=3.10.4,<3.11.0)", "pytz (>=2018.6)"] -passport = ["cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)"] -rate-limiter = ["aiolimiter (>=1.1.0,<1.2.0)"] -socks = ["httpx[socks]"] -webhooks = ["tornado (>=6.4,<7.0)"] - -[[package]] -name = "pytz" -version = "2024.1" -description = "World timezone definitions, modern and historical" -optional = false -python-versions = "*" -files = [ - {file = "pytz-2024.1-py2.py3-none-any.whl", hash = "sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319"}, - {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, -] - [[package]] name = "pyyaml" version = "6.0.1" @@ -1699,7 +1393,6 @@ files = [ [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" -typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.9\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] @@ -1748,17 +1441,6 @@ files = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] -[[package]] -name = "socksio" -version = "1.0.0" -description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." -optional = false -python-versions = ">=3.6" -files = [ - {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, - {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, -] - [[package]] name = "sphinx" version = "7.1.2" @@ -1967,26 +1649,6 @@ files = [ {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, ] -[[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 = "typer" version = "0.9.4" @@ -2030,35 +1692,6 @@ files = [ {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] -[[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 = "tzlocal" -version = "5.2" -description = "tzinfo object for the local timezone" -optional = false -python-versions = ">=3.8" -files = [ - {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, - {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, -] - -[package.dependencies] -"backports.zoneinfo" = {version = "*", markers = "python_version < \"3.9\""} -tzdata = {version = "*", markers = "platform_system == \"Windows\""} - -[package.extras] -devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] - [[package]] name = "urllib3" version = "2.2.1" @@ -2428,5 +2061,5 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" -python-versions = "^3.8.1" -content-hash = "b499862fae8ae3c1d0eb545956d61a68adf7bf987d27007e19ac4f50a2eb78d5" +python-versions = "^3.9,!=3.9.7" +content-hash = "8539df9b57bdf437aebcc0ea06e63d3da12180a44a64282f95a5f903e7d0ab54" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 94c1953a..45427923 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -12,7 +12,7 @@ readme = "README.md" packages = [{include = "chatsky_ui"}] [tool.poetry.dependencies] -python = "^3.8.1" +python = "^3.9,!=3.9.7" fastapi = "^0.110.0" uvicorn = {extras = ["standard"], version = "^0.28.0"} pydantic = "^2.6.3" @@ -20,7 +20,7 @@ typer = "^0.9.0" pydantic-settings = "^2.2.1" aiofiles = "^23.2.1" cookiecutter = "^2.6.0" -chatsky = {version = "1.0.0rc1", extras = ["yaml", "telegram"]} +chatsky = {extras = ["yaml", "telegram"], git = "https://github.com/deeppavlov/chatsky.git", branch = "feat/add-docker-image"} omegaconf = "^2.3.0" httpx = "^0.27.0" httpx-ws = "^0.6.0" From 0a84d80a47df8da6cce484164ade2d3e9fd807d4 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Tue, 19 Nov 2024 16:50:18 +0800 Subject: [PATCH 20/41] fix: Get last flow not last tag with `/flows` --- .../chatsky_ui/api/api_v1/endpoints/flows.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/backend/chatsky_ui/api/api_v1/endpoints/flows.py b/backend/chatsky_ui/api/api_v1/endpoints/flows.py index caddcb29..490f099a 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/flows.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/flows.py @@ -22,15 +22,21 @@ async def flows_get(build_id: Optional[int] = None) -> Dict[str, Union[str, Dict if build_id is not None: tag = int(build_id) + try: + repo.git.checkout(tag, settings.frontend_flows_path.name) + except GitCommandError as e: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail=f"Build_id {tag} not found", + ) from e else: - tag = sorted(repo.tags, key=lambda t: t.commit.committed_datetime)[-1] - try: - repo.git.checkout(tag, settings.frontend_flows_path.name) - except GitCommandError as e: - raise HTTPException( - status_code=status.HTTP_404_NOT_FOUND, - detail=f"Build_id {tag} not found", - ) from e + try: + repo.git.checkout("HEAD", settings.frontend_flows_path.name) + except GitCommandError as e: + raise HTTPException( + status_code=status.HTTP_404_NOT_FOUND, + detail="Failed to checkout the latest commit", + ) from e omega_flows = await read_conf(settings.frontend_flows_path) dict_flows = OmegaConf.to_container(omega_flows, resolve=True) From 6a5ef9ac1e041518383311099795bfc75366200c Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Wed, 20 Nov 2024 14:33:05 +0800 Subject: [PATCH 21/41] chore: Write logs out in case of stopped process --- backend/chatsky_ui/services/process.py | 2 +- backend/poetry.lock | 338 ++++++++++++++++++++++++- 2 files changed, 338 insertions(+), 2 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 96f0b32e..810442c3 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -123,7 +123,7 @@ async def check_status(self) -> Status: ) self.status = Status.FAILED_WITH_UNEXPECTED_CODE - if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE, Status.STOPPED]: + if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: stdout, stderr = await self.process.communicate() if stdout: self.logger.info(f"[stdout]\n{stdout.decode()}") diff --git a/backend/poetry.lock b/backend/poetry.lock index 5e6d4efe..67dfda33 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -11,6 +11,17 @@ files = [ {file = "aiofiles-23.2.1.tar.gz", hash = "sha256:84ec2218d8419404abcb9f0c02df3f34c6e0a68ed41072acfb1cef5cbc29051a"}, ] +[[package]] +name = "aiolimiter" +version = "1.1.0" +description = "asyncio rate limiter, a leaky bucket implementation" +optional = false +python-versions = ">=3.7,<4.0" +files = [ + {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, + {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, +] + [[package]] name = "alabaster" version = "0.7.13" @@ -65,6 +76,34 @@ doc = ["Sphinx (>=7)", "packaging", "sphinx-autodoc-typehints (>=1.2.0)", "sphin 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 = "apscheduler" +version = "3.10.4" +description = "In-process task scheduler with Cron-like capabilities" +optional = false +python-versions = ">=3.6" +files = [ + {file = "APScheduler-3.10.4-py3-none-any.whl", hash = "sha256:fb91e8a768632a4756a585f79ec834e0e27aad5860bac7eaa523d9ccefd87661"}, + {file = "APScheduler-3.10.4.tar.gz", hash = "sha256:e6df071b27d9be898e486bc7940a7be50b4af2e9da7c08f0744a96d4bd4cef4a"}, +] + +[package.dependencies] +pytz = "*" +six = ">=1.4.0" +tzlocal = ">=2.0,<3.dev0 || >=4.dev0" + +[package.extras] +doc = ["sphinx", "sphinx-rtd-theme"] +gevent = ["gevent"] +mongodb = ["pymongo (>=3.0)"] +redis = ["redis (>=3.0)"] +rethinkdb = ["rethinkdb (>=2.4.0)"] +sqlalchemy = ["sqlalchemy (>=1.4)"] +testing = ["pytest", "pytest-asyncio", "pytest-cov", "pytest-tornado5"] +tornado = ["tornado (>=4.3)"] +twisted = ["twisted"] +zookeeper = ["kazoo"] + [[package]] name = "arrow" version = "1.3.0" @@ -161,6 +200,17 @@ d = ["aiohttp (>=3.7.4)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "cachetools" +version = "5.5.0" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.7" +files = [ + {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, + {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, +] + [[package]] name = "certifi" version = "2024.2.2" @@ -172,6 +222,85 @@ files = [ {file = "certifi-2024.2.2.tar.gz", hash = "sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f"}, ] +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "chardet" version = "5.2.0" @@ -296,6 +425,8 @@ colorama = "*" eval_type_backport = "*" nest-asyncio = "*" pydantic = ">=2.0" +python-telegram-bot = {version = "~=21.3", extras = ["all"], optional = true} +pyyaml = {version = "*", optional = true} typing-extensions = "*" wrapt = "*" @@ -318,7 +449,7 @@ ydb = ["six", "ydb"] type = "git" url = "https://github.com/deeppavlov/chatsky.git" reference = "feat/add-docker-image" -resolved_reference = "d4296f00b9369f6e4f9119c7cde5fe7ac71c32f9" +resolved_reference = "51bc913f09c17a89cba253d30393b6c1cdcc0deb" [[package]] name = "click" @@ -453,6 +584,55 @@ tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.1 [package.extras] toml = ["tomli"] +[[package]] +name = "cryptography" +version = "43.0.3" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +files = [ + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, +] + +[package.dependencies] +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + [[package]] name = "dill" version = "0.3.8" @@ -585,6 +765,32 @@ files = [ {file = "h11-0.14.0.tar.gz", hash = "sha256:8f19fbbe99e72420ff35c00b27a34cb9937e902a8b810e2c88300c6f0a3b699d"}, ] +[[package]] +name = "h2" +version = "4.1.0" +description = "HTTP/2 State-Machine based protocol implementation" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "h2-4.1.0-py3-none-any.whl", hash = "sha256:03a46bcf682256c95b5fd9e9a99c1323584c3eec6440d379b9903d709476bc6d"}, + {file = "h2-4.1.0.tar.gz", hash = "sha256:a83aca08fbe7aacb79fec788c9c0bac936343560ed9ec18b82a13a12c28d2abb"}, +] + +[package.dependencies] +hpack = ">=4.0,<5" +hyperframe = ">=6.0,<7" + +[[package]] +name = "hpack" +version = "4.0.0" +description = "Pure-Python HPACK header compression" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hpack-4.0.0-py3-none-any.whl", hash = "sha256:84a076fad3dc9a9f8063ccb8041ef100867b1878b25ef0ee63847a5d53818a6c"}, + {file = "hpack-4.0.0.tar.gz", hash = "sha256:fc41de0c63e687ebffde81187a948221294896f6bdc0ae2312708df339430095"}, +] + [[package]] name = "httpcore" version = "1.0.5" @@ -668,9 +874,11 @@ files = [ [package.dependencies] anyio = "*" certifi = "*" +h2 = {version = ">=3,<5", optional = true, markers = "extra == \"http2\""} httpcore = "==1.*" idna = "*" sniffio = "*" +socksio = {version = "==1.*", optional = true, markers = "extra == \"socks\""} [package.extras] brotli = ["brotli", "brotlicffi"] @@ -695,6 +903,17 @@ httpcore = ">=1.0.4" httpx = ">=0.23.1" wsproto = "*" +[[package]] +name = "hyperframe" +version = "6.0.1" +description = "HTTP/2 framing layer for Python" +optional = false +python-versions = ">=3.6.1" +files = [ + {file = "hyperframe-6.0.1-py3-none-any.whl", hash = "sha256:0ec6bafd80d8ad2195c4f03aacba3a8265e57bc4cff261e802bf39970ed02a15"}, + {file = "hyperframe-6.0.1.tar.gz", hash = "sha256:ae510046231dc8e9ecb1a6586f63d2347bf4c8905914aa84ba585ae85f28a914"}, +] + [[package]] name = "idna" version = "3.7" @@ -993,6 +1212,17 @@ files = [ {file = "pycodestyle-2.8.0.tar.gz", hash = "sha256:eddd5847ef438ea1c7870ca7eb78a9d47ce0cdb4851a5523949f2601d0cbbe7f"}, ] +[[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.0" @@ -1298,6 +1528,53 @@ text-unidecode = ">=1.3" [package.extras] unidecode = ["Unidecode (>=1.1.1)"] +[[package]] +name = "python-telegram-bot" +version = "21.7" +description = "We have made you a wrapper you can't refuse" +optional = false +python-versions = ">=3.9" +files = [ + {file = "python_telegram_bot-21.7-py3-none-any.whl", hash = "sha256:aff1d7245f1b0d4d12d41c9acff74e86d7100713c2204cd02ff17f8d80d18846"}, + {file = "python_telegram_bot-21.7.tar.gz", hash = "sha256:bc8537b77ae02531fc2ad440caafc023fd13f13cf19e592dfa1a9ff84988a012"}, +] + +[package.dependencies] +aiolimiter = {version = ">=1.1.0,<1.2.0", optional = true, markers = "extra == \"all\""} +apscheduler = {version = ">=3.10.4,<3.11.0", optional = true, markers = "extra == \"all\""} +cachetools = {version = ">=5.3.3,<5.6.0", optional = true, markers = "extra == \"all\""} +cffi = {version = ">=1.17.0rc1", optional = true, markers = "python_version > \"3.12\" and extra == \"all\""} +cryptography = {version = ">=39.0.1", optional = true, markers = "extra == \"all\""} +httpx = [ + {version = ">=0.27,<1.0"}, + {version = "*", extras = ["http2"], optional = true, markers = "extra == \"all\""}, + {version = "*", extras = ["socks"], optional = true, markers = "extra == \"all\""}, +] +pytz = {version = ">=2018.6", optional = true, markers = "extra == \"all\""} +tornado = {version = ">=6.4,<7.0", optional = true, markers = "extra == \"all\""} + +[package.extras] +all = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +callback-data = ["cachetools (>=5.3.3,<5.6.0)"] +ext = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +http2 = ["httpx[http2]"] +job-queue = ["apscheduler (>=3.10.4,<3.11.0)", "pytz (>=2018.6)"] +passport = ["cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)"] +rate-limiter = ["aiolimiter (>=1.1.0,<1.2.0)"] +socks = ["httpx[socks]"] +webhooks = ["tornado (>=6.4,<7.0)"] + +[[package]] +name = "pytz" +version = "2024.2" +description = "World timezone definitions, modern and historical" +optional = false +python-versions = "*" +files = [ + {file = "pytz-2024.2-py2.py3-none-any.whl", hash = "sha256:31c7c1817eb7fae7ca4b8c7ee50c72f93aa2dd863de768e1ef4245d426aa0725"}, + {file = "pytz-2024.2.tar.gz", hash = "sha256:2aa355083c50a0f93fa581709deac0c9ad65cca8a9e9beac660adcbd493c798a"}, +] + [[package]] name = "pyyaml" version = "6.0.1" @@ -1441,6 +1718,17 @@ files = [ {file = "snowballstemmer-2.2.0.tar.gz", hash = "sha256:09b16deb8547d3412ad7b590689584cd0fe25ec8db3be37788be3810cbf19cb1"}, ] +[[package]] +name = "socksio" +version = "1.0.0" +description = "Sans-I/O implementation of SOCKS4, SOCKS4A, and SOCKS5." +optional = false +python-versions = ">=3.6" +files = [ + {file = "socksio-1.0.0-py3-none-any.whl", hash = "sha256:95dc1f15f9b34e8d7b16f06d74b8ccf48f609af32ab33c608d08761c5dcbb1f3"}, + {file = "socksio-1.0.0.tar.gz", hash = "sha256:f88beb3da5b5c38b9890469de67d0cb0f9d494b78b106ca1845f96c10b91c4ac"}, +] + [[package]] name = "sphinx" version = "7.1.2" @@ -1649,6 +1937,26 @@ files = [ {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, ] +[[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 = "typer" version = "0.9.4" @@ -1692,6 +2000,34 @@ files = [ {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, ] +[[package]] +name = "tzdata" +version = "2024.2" +description = "Provider of IANA time zone data" +optional = false +python-versions = ">=2" +files = [ + {file = "tzdata-2024.2-py2.py3-none-any.whl", hash = "sha256:a48093786cdcde33cad18c2555e8532f34422074448fbc874186f0abd79565cd"}, + {file = "tzdata-2024.2.tar.gz", hash = "sha256:7d85cc416e9382e69095b7bdf4afd9e3880418a2413feec7069d533d6b4e31cc"}, +] + +[[package]] +name = "tzlocal" +version = "5.2" +description = "tzinfo object for the local timezone" +optional = false +python-versions = ">=3.8" +files = [ + {file = "tzlocal-5.2-py3-none-any.whl", hash = "sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8"}, + {file = "tzlocal-5.2.tar.gz", hash = "sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e"}, +] + +[package.dependencies] +tzdata = {version = "*", markers = "platform_system == \"Windows\""} + +[package.extras] +devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3)", "zest.releaser"] + [[package]] name = "urllib3" version = "2.2.1" From 31d1ef9653d45885a1e1138ed28a66bc69678bc0 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Wed, 20 Nov 2024 19:05:54 +0800 Subject: [PATCH 22/41] test: Fix json-converter tests --- .../front_graph_components/interface.py | 4 ++ backend/chatsky_ui/tests/conftest.py | 8 +-- backend/chatsky_ui/tests/unit/conftest.py | 22 ++++++-- .../tests/unit/test_flow_converter.py | 52 +++++++------------ .../tests/unit/test_node_converer.py | 8 +-- 5 files changed, 45 insertions(+), 49 deletions(-) diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index 5d6cc25c..6493b2ce 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -10,6 +10,10 @@ class Interface(BaseComponent): + model_config = { + "extra": "forbid" + } + telegram: Optional[Dict[str, Any]] = Field(default=None) http: Optional[Dict[str, Any]] = Field(default=None) diff --git a/backend/chatsky_ui/tests/conftest.py b/backend/chatsky_ui/tests/conftest.py index 662ec4a2..2f4d1987 100644 --- a/backend/chatsky_ui/tests/conftest.py +++ b/backend/chatsky_ui/tests/conftest.py @@ -17,7 +17,7 @@ from chatsky_ui.schemas.preset import Preset from chatsky_ui.services.process import RunProcess from chatsky_ui.services.process_manager import BuildManager, RunManager -from chatsky_ui.services.websocket_manager import WebSocketManager + DUMMY_BUILD_ID = -1 @@ -83,9 +83,3 @@ def run_manager(): def build_manager(): return BuildManager() - -@pytest.fixture -def websocket_manager(): - manager = WebSocketManager() - manager.set_logger() - return manager diff --git a/backend/chatsky_ui/tests/unit/conftest.py b/backend/chatsky_ui/tests/unit/conftest.py index 1ca98566..1ccea99b 100644 --- a/backend/chatsky_ui/tests/unit/conftest.py +++ b/backend/chatsky_ui/tests/unit/conftest.py @@ -1,5 +1,6 @@ import pytest +from chatsky import PRE_RESPONSE, RESPONSE, TRANSITIONS, PRE_TRANSITION @pytest.fixture def custom_condition(): @@ -120,6 +121,16 @@ def flow(info_node, group_slot): } +@pytest.fixture +def chatsky_node(converted_custom_response, converted_custom_condition): + return { + PRE_RESPONSE: {"fill": {"chatsky.processing.FillTemplate": None}}, + RESPONSE: converted_custom_response, + TRANSITIONS: [{"dst": "dst_test_node", "priority": 1, "cnd": converted_custom_condition}], + PRE_TRANSITION: {}, + } + + @pytest.fixture def mapped_flow(info_node): return {"test_flow": {"1": info_node}} @@ -128,7 +139,12 @@ def mapped_flow(info_node): @pytest.fixture def telegram_interface(): return { - "telegram": { - "token": "test_token", - } + "telegram": {} + } + + +@pytest.fixture +def chatsky_telegram_interface(): + return { + "chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} } diff --git a/backend/chatsky_ui/tests/unit/test_flow_converter.py b/backend/chatsky_ui/tests/unit/test_flow_converter.py index d81d5b26..cb53310b 100644 --- a/backend/chatsky_ui/tests/unit/test_flow_converter.py +++ b/backend/chatsky_ui/tests/unit/test_flow_converter.py @@ -1,5 +1,6 @@ import pytest from pathlib import Path +import os import yaml from chatsky_ui.services.json_converter_new2.flow_converter import FlowConverter @@ -9,20 +10,10 @@ @pytest.fixture -def chatsky_flow(): +def chatsky_flow(chatsky_node): return { "test_flow": { - "test_node": { - "RESPONSE": {"custom.responses.test_response": None}, - "TRANSITIONS": [ - { - "cnd": {"custom.conditions.test_condition": None}, - "dst": "dst_test_node", - "priority": 1, - } - ], - "PRE_TRANSITION": {}, - } + "test_node": chatsky_node } } @@ -81,51 +72,46 @@ def test_extract_start_fallback_labels_fail_multiple_labels(self, flow, slots_co class TestInterfaceConverter: - def test_interface_converter(self, telegram_interface): - interface = telegram_interface + def test_interface_converter(self, telegram_interface, chatsky_telegram_interface): + os.environ["TG_BOT_TOKEN"] = "some_token" - converted_interface = InterfaceConverter(interface)() + converted_interface = InterfaceConverter(telegram_interface)() - assert converted_interface == { - "chatsky.messengers.telegram.LongpollingInterface": { - "token": "test_token", - } - } - - def test_interface_fail_no_token(self): - interface = {"telegram": {}} + assert converted_interface == chatsky_telegram_interface + def test_interface_fail_no_token(self, telegram_interface): + os.environ.pop("TG_BOT_TOKEN", None) with pytest.raises(ValueError): - InterfaceConverter(interface)() + InterfaceConverter(telegram_interface)() def test_interface_fail_multiple_interfaces(self, telegram_interface): - interface = {**telegram_interface, "cli": {}} + interface = {**telegram_interface, "http": {}} with pytest.raises(ValueError): InterfaceConverter(interface)() class TestPipelineConverter: - def test_pipeline_converter(self, flow, telegram_interface, converted_group_slot, chatsky_flow): + def test_pipeline_converter( + self, flow, telegram_interface, chatsky_telegram_interface, converted_group_slot, chatsky_flow + ): pipeline = {"flows": [flow], "interface": telegram_interface} pipeline_path = Path(__file__).parent / "test_pipeline.yaml" with open(pipeline_path, "w") as file: yaml.dump(pipeline, file) + os.environ["TG_BOT_TOKEN"] = "some_token" - PipelineConverter(pipeline_id=1)(pipeline_path, Path(__file__).parent) + PipelineConverter()(pipeline_path, Path(__file__).parent) - output_file = Path(__file__).parent / "build_1.yaml" + output_file = Path(__file__).parent / "build.yaml" with open(output_file) as file: converted_pipeline = yaml.load(file, Loader=yaml.Loader) output_file.unlink() + pipeline_path.unlink() assert converted_pipeline == { "script": chatsky_flow, - "messenger_interface": { - "chatsky.messengers.telegram.LongpollingInterface": { - "token": "test_token", - } - }, + "messenger_interface": chatsky_telegram_interface, "slots": converted_group_slot, "start_label": ["test_flow", "test_node"], "fallback_label": ["test_flow", "test_node"], diff --git a/backend/chatsky_ui/tests/unit/test_node_converer.py b/backend/chatsky_ui/tests/unit/test_node_converer.py index 45260db9..882e3984 100644 --- a/backend/chatsky_ui/tests/unit/test_node_converer.py +++ b/backend/chatsky_ui/tests/unit/test_node_converer.py @@ -2,14 +2,10 @@ class TestNodeConverter: - def test_info_node_converter(self, info_node, slots_conf, converted_custom_response, converted_custom_condition): + def test_info_node_converter(self, info_node, slots_conf, chatsky_node): converted_node = InfoNodeConverter(info_node)(slots_conf=slots_conf) - assert converted_node == { - "RESPONSE": converted_custom_response, - "TRANSITIONS": [{"dst": "dst_test_node", "priority": 1, "cnd": converted_custom_condition}], - "PRE_TRANSITION": {}, - } + assert converted_node == chatsky_node def test_link_node_converter(self): link_node = { From ca7b30170283d9c00afd151b1525701882c3a0a9 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Wed, 27 Nov 2024 18:01:24 +0800 Subject: [PATCH 23/41] fix: Check aliveness of a tg|http process properly --- .../chatsky_ui/api/api_v1/endpoints/bot.py | 2 +- backend/chatsky_ui/services/process.py | 124 ++++++++++-------- 2 files changed, 70 insertions(+), 56 deletions(-) diff --git a/backend/chatsky_ui/api/api_v1/endpoints/bot.py b/backend/chatsky_ui/api/api_v1/endpoints/bot.py index d9cc003d..6485548d 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/bot.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/bot.py @@ -250,5 +250,5 @@ async def respond( except Exception as e: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, - detail=f"Please check that service's up and running on the port '{HTTP_INTERFACE_PORT}' that you're trying to reach.", + detail=f"Please check that service's up and running on the port '{HTTP_INTERFACE_PORT}'.", ) from e diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 810442c3..fd68c50c 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -11,6 +11,8 @@ from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional +from httpx import AsyncClient +from chatsky.messengers.http_interface import HTTP_INTERFACE_PORT from dotenv import load_dotenv @@ -25,14 +27,6 @@ PING_PONG_TIMEOUT = float(os.getenv("PING_PONG_TIMEOUT", 0.5)) -def _map_to_str(params: Dict[str, Any]): - for k, v in params.items(): - if isinstance(v, datetime): - params[k] = v.strftime("%Y-%m-%dT%H:%M:%S") - elif isinstance(v, Path): - params[k] = str(v) - - class Process(ABC): """Base for build and run processes.""" @@ -65,12 +59,20 @@ async def get_full_info(self, attributes: list) -> Dict[str, Any]: Returns: dict: A dictionary containing the values of the attributes mentioned in the list. """ + def _map_to_str(params: Dict[str, Any]): + for k, v in params.copy().items(): + if isinstance(v, datetime): + params[k] = v.strftime("%Y-%m-%dT%H:%M:%S") + elif isinstance(v, Path): + params[k] = str(v) + return params + await self.check_status() info = {key: getattr(self, key) for key in self.__dict__ if key in attributes} if "status" in attributes: info["status"] = self.status.value - return info + return _map_to_str(info) @abstractmethod async def update_db_info(self): @@ -123,12 +125,12 @@ async def check_status(self) -> Status: ) self.status = Status.FAILED_WITH_UNEXPECTED_CODE - if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: - stdout, stderr = await self.process.communicate() - if stdout: - self.logger.info(f"[stdout]\n{stdout.decode()}") - if stderr: - self.logger.error(f"[stderr]\n{stderr.decode()}") + # if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: + # stdout, stderr = await self.process.communicate() + # if stdout: + # self.logger.info(f"[stdout]\n{stdout.decode()}") + # if stderr: + # self.logger.error(f"[stderr]\n{stderr.decode()}") return self.status @@ -158,29 +160,57 @@ async def stop(self) -> None: self.logger.error("Process '%s' not found. It may have already exited.", self.id) raise ProcessLookupError from exc - async def read_stdout(self) -> bytes: - """Reads the stdout of the process for communication.""" - async with self.lock: - if self.process is None: - self.logger.error("Cannot read stdout from a process '%s' that has not started yet.", self.id) - raise RuntimeError - if self.process.stdout is None: - raise RuntimeError(f"The process '{self.id}' stdout is None. It might be still running.") - return await self.process.stdout.readline() - - async def write_stdin(self, message: bytes) -> None: - """Writes a message to the stdin of the process for communication.""" - if self.process is None: - self.logger.error("Cannot write into stdin of a process '%s' that has not started yet.", self.id) - raise RuntimeError - if self.process.stdin is None: - raise RuntimeError(f"The process '{self.id}' stdin is None. It might be still running.") - self.process.stdin.write(message) - await self.process.stdin.drain() - async def is_alive(self) -> bool: """Checks if the process is alive by writing to stdin andreading its stdout.""" - return True + async def check_telegram_readiness(stream, name): + async for line in stream: + decoded_line = line.decode().strip() + self.logger.info(f"[{name}] {decoded_line}") + + if "telegram.ext.Application:Application started" in decoded_line: + self.logger.info("The application is ready for use!") + return True + return False + + async with AsyncClient() as client: + try: + response = await client.get( + f"http://localhost:{HTTP_INTERFACE_PORT}/health", + ) + return response.json()["status"] == "ok" + except Exception as e: + self.logger.info( + f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " + f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" + ) + + done, pending = await asyncio.wait( + [ + asyncio.create_task(check_telegram_readiness(self.process.stdout, "STDOUT")), + asyncio.create_task(check_telegram_readiness(self.process.stderr, "STDERR")), + ], + return_when=asyncio.FIRST_COMPLETED, + timeout=PING_PONG_TIMEOUT, + ) + + for task in pending: + task.cancel() + + for task in done: + result = task.result() + if result: + return result + + def add_new_conf(self, conf: list, params: dict) -> list: #TODO: rename conf everywhere to metadata/meta + for run in conf: + if run.id == params["id"]: # type: ignore + for key, value in params.items(): + setattr(run, key, value) + break + else: + conf.append(params) + + return conf class RunProcess(Process): @@ -202,17 +232,9 @@ async def update_db_info(self) -> None: # save current run info into runs_path self.logger.debug("Updating db run info") runs_conf = await read_conf(settings.runs_path) - run_params = await self.get_full_info() - _map_to_str(run_params) - for run in runs_conf: - if run.id == run_params["id"]: # type: ignore - for key, value in run_params.items(): - setattr(run, key, value) - break - else: - runs_conf.append(run_params) + runs_conf = self.add_new_conf(runs_conf, run_params) # type: ignore await write_conf(runs_conf, settings.runs_path) @@ -243,18 +265,10 @@ async def get_full_info(self, attributes: Optional[list] = None) -> Dict[str, An return await super().get_full_info(attributes) async def update_db_info(self) -> None: - # save current build info into builds_path + """Saves current build info into builds_path""" builds_conf = await read_conf(settings.builds_path) - build_params = await self.get_full_info() - _map_to_str(build_params) - for build in builds_conf: - if build.id == build_params["id"]: # type: ignore - for key, value in build_params.items(): - setattr(build, key, value) - break - else: - builds_conf.append(build_params) + builds_conf = self.add_new_conf(builds_conf, build_params) # type: ignore await write_conf(builds_conf, settings.builds_path) From 1767b4f292e06da66ad35aba839630ecdcd1a1ff Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Thu, 28 Nov 2024 19:01:13 +0800 Subject: [PATCH 24/41] fix: Version with git only when using UI --- backend/chatsky_ui/cli.py | 39 +++++------------ .../front_graph_components/interface.py | 3 +- backend/chatsky_ui/services/process.py | 17 ++++---- .../chatsky_ui/services/process_manager.py | 43 ++++++++++++++++--- 4 files changed, 59 insertions(+), 43 deletions(-) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 1c44e3a1..65011566 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -10,6 +10,7 @@ from cookiecutter.main import cookiecutter from typing_extensions import Annotated from git import Repo +from typing import Optional # Patch nest_asyncio before importing Chatsky nest_asyncio.apply = lambda: None @@ -62,7 +63,7 @@ async def _execute_command(command_to_run): sys.exit(1) -def _execute_command_file(build_id: int, project_dir: Path, command_file: str, preset: str): +def _execute_command_file(project_dir: Path, command_file: str, preset: str, build_id: Optional[int] = None): logger = get_logger(__name__) presets_build_path = settings.presets / command_file @@ -84,7 +85,6 @@ def _execute_command_file(build_id: int, project_dir: Path, command_file: str, p @cli.command("build_bot") def build_bot( - build_id: Annotated[int, typer.Option(help="Id to save the build with")] = None, project_dir: Path = None, preset: Annotated[str, typer.Option(help="Could be one of: success, failure, loop")] = "success", ): @@ -95,12 +95,11 @@ def build_bot( raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - _execute_command_file(build_id, project_dir, "build.json", preset) + _execute_command_file(project_dir, "build.json", preset) @cli.command("build_scenario") def build_scenario( - build_id: Annotated[int, typer.Argument(help="Id to save the build with")], project_dir: Annotated[Path, typer.Option(help="Your Chatsky-UI project directory")] = ".", # TODO: add custom_dir - maybe the same way like project_dir ): @@ -108,31 +107,15 @@ def build_scenario( if not project_dir.is_dir(): raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - logger = get_logger(__name__) - bot_repo = get_repo(Path(project_dir) / "bot") - chatsky_ui_repo = get_repo(settings.frontend_flows_path.parent) - # check that there's no already existing tag {build_id} - for tag in bot_repo.tags: - if tag.name == str(build_id): - raise ValueError(f"Tag {build_id} already exists") - - is_changed = save_frontend_graph_to_git(build_id, chatsky_ui_repo) - if is_changed: - from chatsky_ui.services.json_converter_new2.pipeline_converter import ( - PipelineConverter, - ) # pylint: disable=C0415 - - pipeline_converter = PipelineConverter() - pipeline_converter( - input_file=settings.frontend_flows_path, output_dir=settings.scripts_dir - ) # TODO: rename to frontend_graph_path - logger.info("Graph is changed. Gonna build") - else: - logger.info("Graph isn't changed. Ain't gonna build") + from chatsky_ui.services.json_converter_new2.pipeline_converter import ( + PipelineConverter, + ) # pylint: disable=C0415 - # Save the project anyway to keep a gradual number of builds - save_built_script_to_git(build_id, bot_repo) + pipeline_converter = PipelineConverter() + pipeline_converter( + input_file=settings.frontend_flows_path, output_dir=settings.scripts_dir + ) # TODO: rename to frontend_graph_path @cli.command("run_bot") @@ -148,7 +131,7 @@ def run_bot( raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - _execute_command_file(build_id, project_dir, "run.json", preset) + _execute_command_file(project_dir, "run.json", preset, build_id) @cli.command("run_scenario") diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index 6493b2ce..a11a7b57 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -9,6 +9,8 @@ from chatsky_ui.core.config import settings +load_dotenv(os.path.join(settings.work_directory, ".env")) + class Interface(BaseComponent): model_config = { "extra": "forbid" @@ -26,7 +28,6 @@ def check_one_not_none(cls, values): @model_validator(mode="after") def check_telegram_token(cls, values): - load_dotenv(os.path.join(settings.work_directory, ".env")) tg_bot_token = os.getenv("TG_BOT_TOKEN") if values.telegram is not None and not tg_bot_token: raise ValueError("Telegram token must be provided.") diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index fd68c50c..654f7af9 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -37,7 +37,7 @@ def __init__(self, id_: int, preset_end_status: str = ""): self.timestamp: datetime = datetime.now() self.log_path: Path self.lock: asyncio.Lock = asyncio.Lock() - self.process: asyncio.subprocess.Process # pylint: disable=no-member #TODO: is naming ok? + self.process: Optional[asyncio.subprocess.Process] = None self.logger: logging.Logger async def start(self, cmd_to_run: str) -> None: @@ -83,7 +83,7 @@ async def periodically_check_status(self) -> None: while True: await self.update_db_info() # check status and update db self.logger.info("Status of process '%s': %s", self.id, self.status) - if self.status in [Status.STOPPED, Status.COMPLETED, Status.FAILED]: + if self.status in [Status.NULL, Status.STOPPED, Status.COMPLETED, Status.FAILED]: break await asyncio.sleep(2) # TODO: ?sleep time shouldn't be constant @@ -102,6 +102,7 @@ async def check_status(self) -> Status: """ if self.process is None: self.status = Status.NULL + return self.status # if process is already alive, don't interrupt potential open channels by checking status periodically. elif self.process.returncode is None: if self.status == Status.ALIVE: @@ -125,12 +126,12 @@ async def check_status(self) -> Status: ) self.status = Status.FAILED_WITH_UNEXPECTED_CODE - # if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: - # stdout, stderr = await self.process.communicate() - # if stdout: - # self.logger.info(f"[stdout]\n{stdout.decode()}") - # if stderr: - # self.logger.error(f"[stderr]\n{stderr.decode()}") + if self.status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: + stdout, stderr = await self.process.communicate() + if stdout: + self.logger.info(f"[stdout]\n{stdout.decode()}") + if stderr: + self.logger.error(f"[stderr]\n{stderr.decode()}") return self.status diff --git a/backend/chatsky_ui/services/process_manager.py b/backend/chatsky_ui/services/process_manager.py index 38746cb9..78aa8cd9 100644 --- a/backend/chatsky_ui/services/process_manager.py +++ b/backend/chatsky_ui/services/process_manager.py @@ -17,6 +17,7 @@ from chatsky_ui.schemas.preset import Preset from chatsky_ui.schemas.process_status import Status from chatsky_ui.services.process import BuildProcess, RunProcess +from chatsky_ui.utils.git_cmd import get_repo, save_frontend_graph_to_git, save_built_script_to_git class ProcessManager: @@ -175,14 +176,22 @@ async def start(self, preset: Preset) -> int: self.last_id = max([build["id"] for build in await self.get_full_info(0, 10000)]) self.last_id += 1 id_ = self.last_id + + if self.is_repeated_id(id_): + raise ValueError(f"Build id '{id_}' already exists in the database") + process = BuildProcess(id_, preset.end_status) - cmd_to_run = ( - f"chatsky.ui build_bot --build-id {id_} " - f"--preset {preset.end_status} " - f"--project-dir {settings.work_directory}" - ) - await process.start(cmd_to_run) + if self.is_changed_graph(id_): + cmd_to_run = ( + f"chatsky.ui build_bot " + f"--preset {preset.end_status} " + f"--project-dir {settings.work_directory}" + ) + await process.start(cmd_to_run) self.processes[id_] = process + + # Save the project anyway to keep a gradual number of builds + self.save_built_script_to_git(id_) return self.last_id @@ -194,6 +203,28 @@ async def check_status(self, id_, *args, **kwargs): """ await self.processes[id_].periodically_check_status() + def is_repeated_id(self, id_: int) -> bool: + bot_repo = get_repo(settings.custom_dir.parent) + + for tag in bot_repo.tags: + if tag.name == str(id_): + return True + return False + + def is_changed_graph(self, id_: int) -> bool: + chatsky_ui_repo = get_repo(settings.frontend_flows_path.parent) + is_changed = save_frontend_graph_to_git(id_, chatsky_ui_repo) + if is_changed: + self.logger.info("Graph is changed. Gonna build") + return True + else: + self.logger.info("Graph isn't changed. Ain't gonna build") + return False + + def save_built_script_to_git(self, id_: int) -> None: + bot_repo = get_repo(settings.custom_dir.parent) + save_built_script_to_git(id_, bot_repo) + async def get_build_info(self, id_: int, run_manager: RunManager) -> Optional[Dict[str, Any]]: """Returns metadata of a specific build process identified by its unique ID. From ba5b4a97405df4dd6674a47934975d2bd4499bb1 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 13:12:52 +0800 Subject: [PATCH 25/41] fix: Save built script after end of process --- backend/chatsky_ui/services/process.py | 34 ++-- .../chatsky_ui/services/process_manager.py | 9 +- backend/poetry.lock | 165 +++++++++--------- 3 files changed, 104 insertions(+), 104 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 654f7af9..973f1992 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -20,6 +20,8 @@ from chatsky_ui.core.logger_config import get_logger, setup_logging from chatsky_ui.db.base import read_conf, write_conf from chatsky_ui.schemas.process_status import Status +from chatsky_ui.utils.git_cmd import get_repo, save_frontend_graph_to_git, save_built_script_to_git + load_dotenv() @@ -173,17 +175,17 @@ async def check_telegram_readiness(stream, name): return True return False - async with AsyncClient() as client: - try: - response = await client.get( - f"http://localhost:{HTTP_INTERFACE_PORT}/health", - ) - return response.json()["status"] == "ok" - except Exception as e: - self.logger.info( - f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " - f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" - ) + # async with AsyncClient() as client: + # try: + # response = await client.get( + # f"http://localhost:{HTTP_INTERFACE_PORT}/health", + # ) + # return response.json()["status"] == "ok" + # except Exception as e: + # self.logger.info( + # f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " + # f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" + # ) done, pending = await asyncio.wait( [ @@ -273,3 +275,13 @@ async def update_db_info(self) -> None: builds_conf = self.add_new_conf(builds_conf, build_params) # type: ignore await write_conf(builds_conf, settings.builds_path) + + def save_built_script_to_git(self, id_: int) -> None: + bot_repo = get_repo(settings.custom_dir.parent) + save_built_script_to_git(id_, bot_repo) + + async def check_status(self) -> Status: + status = await super().check_status() + if status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: + # Save the project anyway to keep a gradual number of builds + self.save_built_script_to_git(self.id) diff --git a/backend/chatsky_ui/services/process_manager.py b/backend/chatsky_ui/services/process_manager.py index 78aa8cd9..8184fc7d 100644 --- a/backend/chatsky_ui/services/process_manager.py +++ b/backend/chatsky_ui/services/process_manager.py @@ -17,7 +17,7 @@ from chatsky_ui.schemas.preset import Preset from chatsky_ui.schemas.process_status import Status from chatsky_ui.services.process import BuildProcess, RunProcess -from chatsky_ui.utils.git_cmd import get_repo, save_frontend_graph_to_git, save_built_script_to_git +from chatsky_ui.utils.git_cmd import get_repo, save_frontend_graph_to_git class ProcessManager: @@ -190,9 +190,6 @@ async def start(self, preset: Preset) -> int: await process.start(cmd_to_run) self.processes[id_] = process - # Save the project anyway to keep a gradual number of builds - self.save_built_script_to_git(id_) - return self.last_id async def check_status(self, id_, *args, **kwargs): @@ -221,10 +218,6 @@ def is_changed_graph(self, id_: int) -> bool: self.logger.info("Graph isn't changed. Ain't gonna build") return False - def save_built_script_to_git(self, id_: int) -> None: - bot_repo = get_repo(settings.custom_dir.parent) - save_built_script_to_git(id_, bot_repo) - async def get_build_info(self, id_: int, run_manager: RunManager) -> Optional[Dict[str, Any]]: """Returns metadata of a specific build process identified by its unique ID. diff --git a/backend/poetry.lock b/backend/poetry.lock index 67dfda33..f35c43b7 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -449,7 +449,7 @@ ydb = ["six", "ydb"] type = "git" url = "https://github.com/deeppavlov/chatsky.git" reference = "feat/add-docker-image" -resolved_reference = "51bc913f09c17a89cba253d30393b6c1cdcc0deb" +resolved_reference = "584d06b233c0ebf068533a6afb7103d26eb73dfe" [[package]] name = "click" @@ -1939,22 +1939,22 @@ files = [ [[package]] name = "tornado" -version = "6.4.1" +version = "6.4.2" 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"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:e828cce1123e9e44ae2a50a9de3055497ab1d0aeb440c5ac23064d9e44880da1"}, + {file = "tornado-6.4.2-cp38-abi3-macosx_10_9_x86_64.whl", hash = "sha256:072ce12ada169c5b00b7d92a99ba089447ccc993ea2143c9ede887e0937aa803"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a017d239bd1bb0919f72af256a970624241f070496635784d9bf0db640d3fec"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c36e62ce8f63409301537222faffcef7dfc5284f27eec227389f2ad11b09d946"}, + {file = "tornado-6.4.2-cp38-abi3-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bca9eb02196e789c9cb5c3c7c0f04fb447dc2adffd95265b2c7223a8a615ccbf"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:304463bd0772442ff4d0f5149c6f1c2135a1fae045adf070821c6cdc76980634"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c82c46813ba483a385ab2a99caeaedf92585a1f90defb5693351fa7e4ea0bf73"}, + {file = "tornado-6.4.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:932d195ca9015956fa502c6b56af9eb06106140d844a335590c1ec7f5277d10c"}, + {file = "tornado-6.4.2-cp38-abi3-win32.whl", hash = "sha256:2876cef82e6c5978fde1e0d5b1f919d756968d5b4282418f3146b79b58556482"}, + {file = "tornado-6.4.2-cp38-abi3-win_amd64.whl", hash = "sha256:908b71bf3ff37d81073356a5fadcc660eb10c1476ee6e2725588626ce7e5ca38"}, + {file = "tornado-6.4.2.tar.gz", hash = "sha256:92bad5b4746e9879fd7bf1eb21dce4e3fc5128d71601f80005afa39237ad620b"}, ] [[package]] @@ -2285,81 +2285,76 @@ files = [ [[package]] name = "wrapt" -version = "1.16.0" +version = "1.17.0" description = "Module for decorators, wrappers and monkey patching." optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "wrapt-1.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ffa565331890b90056c01db69c0fe634a776f8019c143a5ae265f9c6bc4bd6d4"}, - {file = "wrapt-1.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e4fdb9275308292e880dcbeb12546df7f3e0f96c6b41197e0cf37d2826359020"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bb2dee3874a500de01c93d5c71415fcaef1d858370d405824783e7a8ef5db440"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a88e6010048489cda82b1326889ec075a8c856c2e6a256072b28eaee3ccf487"}, - {file = "wrapt-1.16.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac83a914ebaf589b69f7d0a1277602ff494e21f4c2f743313414378f8f50a4cf"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:73aa7d98215d39b8455f103de64391cb79dfcad601701a3aa0dddacf74911d72"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:807cc8543a477ab7422f1120a217054f958a66ef7314f76dd9e77d3f02cdccd0"}, - {file = "wrapt-1.16.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:bf5703fdeb350e36885f2875d853ce13172ae281c56e509f4e6eca049bdfb136"}, - {file = "wrapt-1.16.0-cp310-cp310-win32.whl", hash = "sha256:f6b2d0c6703c988d334f297aa5df18c45e97b0af3679bb75059e0e0bd8b1069d"}, - {file = "wrapt-1.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:decbfa2f618fa8ed81c95ee18a387ff973143c656ef800c9f24fb7e9c16054e2"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1a5db485fe2de4403f13fafdc231b0dbae5eca4359232d2efc79025527375b09"}, - {file = "wrapt-1.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:75ea7d0ee2a15733684badb16de6794894ed9c55aa5e9903260922f0482e687d"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a452f9ca3e3267cd4d0fcf2edd0d035b1934ac2bd7e0e57ac91ad6b95c0c6389"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:43aa59eadec7890d9958748db829df269f0368521ba6dc68cc172d5d03ed8060"}, - {file = "wrapt-1.16.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:72554a23c78a8e7aa02abbd699d129eead8b147a23c56e08d08dfc29cfdddca1"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:d2efee35b4b0a347e0d99d28e884dfd82797852d62fcd7ebdeee26f3ceb72cf3"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:6dcfcffe73710be01d90cae08c3e548d90932d37b39ef83969ae135d36ef3956"}, - {file = "wrapt-1.16.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:eb6e651000a19c96f452c85132811d25e9264d836951022d6e81df2fff38337d"}, - {file = "wrapt-1.16.0-cp311-cp311-win32.whl", hash = "sha256:66027d667efe95cc4fa945af59f92c5a02c6f5bb6012bff9e60542c74c75c362"}, - {file = "wrapt-1.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:aefbc4cb0a54f91af643660a0a150ce2c090d3652cf4052a5397fb2de549cd89"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5eb404d89131ec9b4f748fa5cfb5346802e5ee8836f57d516576e61f304f3b7b"}, - {file = "wrapt-1.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9090c9e676d5236a6948330e83cb89969f433b1943a558968f659ead07cb3b36"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:94265b00870aa407bd0cbcfd536f17ecde43b94fb8d228560a1e9d3041462d73"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f2058f813d4f2b5e3a9eb2eb3faf8f1d99b81c3e51aeda4b168406443e8ba809"}, - {file = "wrapt-1.16.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b5e1f498a8ca1858a1cdbffb023bfd954da4e3fa2c0cb5853d40014557248b"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:49aac49dc4782cb04f58986e81ea0b4768e4ff197b57324dcbd7699c5dfb40b9"}, - {file = "wrapt-1.16.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:418abb18146475c310d7a6dc71143d6f7adec5b004ac9ce08dc7a34e2babdc5c"}, - {file = "wrapt-1.16.0-cp312-cp312-win32.whl", hash = "sha256:685f568fa5e627e93f3b52fda002c7ed2fa1800b50ce51f6ed1d572d8ab3e7fc"}, - {file = "wrapt-1.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:dcdba5c86e368442528f7060039eda390cc4091bfd1dca41e8046af7c910dda8"}, - {file = "wrapt-1.16.0-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:d462f28826f4657968ae51d2181a074dfe03c200d6131690b7d65d55b0f360f8"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a33a747400b94b6d6b8a165e4480264a64a78c8a4c734b62136062e9a248dd39"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3646eefa23daeba62643a58aac816945cadc0afaf21800a1421eeba5f6cfb9c"}, - {file = "wrapt-1.16.0-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ebf019be5c09d400cf7b024aa52b1f3aeebeff51550d007e92c3c1c4afc2a40"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:1acd723ee2a8826f3d53910255643e33673e1d11db84ce5880675954183ec47e"}, - {file = "wrapt-1.16.0-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:bc57efac2da352a51cc4658878a68d2b1b67dbe9d33c36cb826ca449d80a8465"}, - {file = "wrapt-1.16.0-cp36-cp36m-win32.whl", hash = "sha256:da4813f751142436b075ed7aa012a8778aa43a99f7b36afe9b742d3ed8bdc95e"}, - {file = "wrapt-1.16.0-cp36-cp36m-win_amd64.whl", hash = "sha256:6f6eac2360f2d543cc875a0e5efd413b6cbd483cb3ad7ebf888884a6e0d2e966"}, - {file = "wrapt-1.16.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a0ea261ce52b5952bf669684a251a66df239ec6d441ccb59ec7afa882265d593"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7bd2d7ff69a2cac767fbf7a2b206add2e9a210e57947dd7ce03e25d03d2de292"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9159485323798c8dc530a224bd3ffcf76659319ccc7bbd52e01e73bd0241a0c5"}, - {file = "wrapt-1.16.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a86373cf37cd7764f2201b76496aba58a52e76dedfaa698ef9e9688bfd9e41cf"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:73870c364c11f03ed072dda68ff7aea6d2a3a5c3fe250d917a429c7432e15228"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:b935ae30c6e7400022b50f8d359c03ed233d45b725cfdd299462f41ee5ffba6f"}, - {file = "wrapt-1.16.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:db98ad84a55eb09b3c32a96c576476777e87c520a34e2519d3e59c44710c002c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win32.whl", hash = "sha256:9153ed35fc5e4fa3b2fe97bddaa7cbec0ed22412b85bcdaf54aeba92ea37428c"}, - {file = "wrapt-1.16.0-cp37-cp37m-win_amd64.whl", hash = "sha256:66dfbaa7cfa3eb707bbfcd46dab2bc6207b005cbc9caa2199bcbc81d95071a00"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1dd50a2696ff89f57bd8847647a1c363b687d3d796dc30d4dd4a9d1689a706f0"}, - {file = "wrapt-1.16.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:44a2754372e32ab315734c6c73b24351d06e77ffff6ae27d2ecf14cf3d229202"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e9723528b9f787dc59168369e42ae1c3b0d3fadb2f1a71de14531d321ee05b0"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dbed418ba5c3dce92619656802cc5355cb679e58d0d89b50f116e4a9d5a9603e"}, - {file = "wrapt-1.16.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:941988b89b4fd6b41c3f0bfb20e92bd23746579736b7343283297c4c8cbae68f"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:6a42cd0cfa8ffc1915aef79cb4284f6383d8a3e9dcca70c445dcfdd639d51267"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:1ca9b6085e4f866bd584fb135a041bfc32cab916e69f714a7d1d397f8c4891ca"}, - {file = "wrapt-1.16.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:d5e49454f19ef621089e204f862388d29e6e8d8b162efce05208913dde5b9ad6"}, - {file = "wrapt-1.16.0-cp38-cp38-win32.whl", hash = "sha256:c31f72b1b6624c9d863fc095da460802f43a7c6868c5dda140f51da24fd47d7b"}, - {file = "wrapt-1.16.0-cp38-cp38-win_amd64.whl", hash = "sha256:490b0ee15c1a55be9c1bd8609b8cecd60e325f0575fc98f50058eae366e01f41"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9b201ae332c3637a42f02d1045e1d0cccfdc41f1f2f801dafbaa7e9b4797bfc2"}, - {file = "wrapt-1.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:2076fad65c6736184e77d7d4729b63a6d1ae0b70da4868adeec40989858eb3fb"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5cd603b575ebceca7da5a3a251e69561bec509e0b46e4993e1cac402b7247b8"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b47cfad9e9bbbed2339081f4e346c93ecd7ab504299403320bf85f7f85c7d46c"}, - {file = "wrapt-1.16.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f8212564d49c50eb4565e502814f694e240c55551a5f1bc841d4fcaabb0a9b8a"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:5f15814a33e42b04e3de432e573aa557f9f0f56458745c2074952f564c50e664"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db2e408d983b0e61e238cf579c09ef7020560441906ca990fe8412153e3b291f"}, - {file = "wrapt-1.16.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:edfad1d29c73f9b863ebe7082ae9321374ccb10879eeabc84ba3b69f2579d537"}, - {file = "wrapt-1.16.0-cp39-cp39-win32.whl", hash = "sha256:ed867c42c268f876097248e05b6117a65bcd1e63b779e916fe2e33cd6fd0d3c3"}, - {file = "wrapt-1.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:eb1b046be06b0fce7249f1d025cd359b4b80fc1c3e24ad9eca33e0dcdb2e4a35"}, - {file = "wrapt-1.16.0-py3-none-any.whl", hash = "sha256:6906c4100a8fcbf2fa735f6059214bb13b97f75b1a61777fcf6432121ef12ef1"}, - {file = "wrapt-1.16.0.tar.gz", hash = "sha256:5f370f952971e7d17c7d1ead40e49f32345a7f7a5373571ef44d800d06b1899d"}, + {file = "wrapt-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a0c23b8319848426f305f9cb0c98a6e32ee68a36264f45948ccf8e7d2b941f8"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b1ca5f060e205f72bec57faae5bd817a1560fcfc4af03f414b08fa29106b7e2d"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e185ec6060e301a7e5f8461c86fb3640a7beb1a0f0208ffde7a65ec4074931df"}, + {file = "wrapt-1.17.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb90765dd91aed05b53cd7a87bd7f5c188fcd95960914bae0d32c5e7f899719d"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:879591c2b5ab0a7184258274c42a126b74a2c3d5a329df16d69f9cee07bba6ea"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fce6fee67c318fdfb7f285c29a82d84782ae2579c0e1b385b7f36c6e8074fffb"}, + {file = "wrapt-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:0698d3a86f68abc894d537887b9bbf84d29bcfbc759e23f4644be27acf6da301"}, + {file = "wrapt-1.17.0-cp310-cp310-win32.whl", hash = "sha256:69d093792dc34a9c4c8a70e4973a3361c7a7578e9cd86961b2bbf38ca71e4e22"}, + {file = "wrapt-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:f28b29dc158ca5d6ac396c8e0a2ef45c4e97bb7e65522bfc04c989e6fe814575"}, + {file = "wrapt-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:74bf625b1b4caaa7bad51d9003f8b07a468a704e0644a700e936c357c17dd45a"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0f2a28eb35cf99d5f5bd12f5dd44a0f41d206db226535b37b0c60e9da162c3ed"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81b1289e99cf4bad07c23393ab447e5e96db0ab50974a280f7954b071d41b489"}, + {file = "wrapt-1.17.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9f2939cd4a2a52ca32bc0b359015718472d7f6de870760342e7ba295be9ebaf9"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6a9653131bda68a1f029c52157fd81e11f07d485df55410401f745007bd6d339"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:4e4b4385363de9052dac1a67bfb535c376f3d19c238b5f36bddc95efae15e12d"}, + {file = "wrapt-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bdf62d25234290db1837875d4dceb2151e4ea7f9fff2ed41c0fde23ed542eb5b"}, + {file = "wrapt-1.17.0-cp311-cp311-win32.whl", hash = "sha256:5d8fd17635b262448ab8f99230fe4dac991af1dabdbb92f7a70a6afac8a7e346"}, + {file = "wrapt-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:92a3d214d5e53cb1db8b015f30d544bc9d3f7179a05feb8f16df713cecc2620a"}, + {file = "wrapt-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:89fc28495896097622c3fc238915c79365dd0ede02f9a82ce436b13bd0ab7569"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:875d240fdbdbe9e11f9831901fb8719da0bd4e6131f83aa9f69b96d18fae7504"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5ed16d95fd142e9c72b6c10b06514ad30e846a0d0917ab406186541fe68b451"}, + {file = "wrapt-1.17.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:18b956061b8db634120b58f668592a772e87e2e78bc1f6a906cfcaa0cc7991c1"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:daba396199399ccabafbfc509037ac635a6bc18510ad1add8fd16d4739cdd106"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4d63f4d446e10ad19ed01188d6c1e1bb134cde8c18b0aa2acfd973d41fcc5ada"}, + {file = "wrapt-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8a5e7cc39a45fc430af1aefc4d77ee6bad72c5bcdb1322cfde852c15192b8bd4"}, + {file = "wrapt-1.17.0-cp312-cp312-win32.whl", hash = "sha256:0a0a1a1ec28b641f2a3a2c35cbe86c00051c04fffcfcc577ffcdd707df3f8635"}, + {file = "wrapt-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:3c34f6896a01b84bab196f7119770fd8466c8ae3dfa73c59c0bb281e7b588ce7"}, + {file = "wrapt-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:714c12485aa52efbc0fc0ade1e9ab3a70343db82627f90f2ecbc898fdf0bb181"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da427d311782324a376cacb47c1a4adc43f99fd9d996ffc1b3e8529c4074d393"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba1739fb38441a27a676f4de4123d3e858e494fac05868b7a281c0a383c098f4"}, + {file = "wrapt-1.17.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e711fc1acc7468463bc084d1b68561e40d1eaa135d8c509a65dd534403d83d7b"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:140ea00c87fafc42739bd74a94a5a9003f8e72c27c47cd4f61d8e05e6dec8721"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:73a96fd11d2b2e77d623a7f26e004cc31f131a365add1ce1ce9a19e55a1eef90"}, + {file = "wrapt-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:0b48554952f0f387984da81ccfa73b62e52817a4386d070c75e4db7d43a28c4a"}, + {file = "wrapt-1.17.0-cp313-cp313-win32.whl", hash = "sha256:498fec8da10e3e62edd1e7368f4b24aa362ac0ad931e678332d1b209aec93045"}, + {file = "wrapt-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:fd136bb85f4568fffca995bd3c8d52080b1e5b225dbf1c2b17b66b4c5fa02838"}, + {file = "wrapt-1.17.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:17fcf043d0b4724858f25b8826c36e08f9fb2e475410bece0ec44a22d533da9b"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e4a557d97f12813dc5e18dad9fa765ae44ddd56a672bb5de4825527c847d6379"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0229b247b0fc7dee0d36176cbb79dbaf2a9eb7ecc50ec3121f40ef443155fb1d"}, + {file = "wrapt-1.17.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8425cfce27b8b20c9b89d77fb50e368d8306a90bf2b6eef2cdf5cd5083adf83f"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9c900108df470060174108012de06d45f514aa4ec21a191e7ab42988ff42a86c"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:4e547b447073fc0dbfcbff15154c1be8823d10dab4ad401bdb1575e3fdedff1b"}, + {file = "wrapt-1.17.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:914f66f3b6fc7b915d46c1cc424bc2441841083de01b90f9e81109c9759e43ab"}, + {file = "wrapt-1.17.0-cp313-cp313t-win32.whl", hash = "sha256:a4192b45dff127c7d69b3bdfb4d3e47b64179a0b9900b6351859f3001397dabf"}, + {file = "wrapt-1.17.0-cp313-cp313t-win_amd64.whl", hash = "sha256:4f643df3d4419ea3f856c5c3f40fec1d65ea2e89ec812c83f7767c8730f9827a"}, + {file = "wrapt-1.17.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:69c40d4655e078ede067a7095544bcec5a963566e17503e75a3a3e0fe2803b13"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f495b6754358979379f84534f8dd7a43ff8cff2558dcdea4a148a6e713a758f"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:baa7ef4e0886a6f482e00d1d5bcd37c201b383f1d314643dfb0367169f94f04c"}, + {file = "wrapt-1.17.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fc931382e56627ec4acb01e09ce66e5c03c384ca52606111cee50d931a342d"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:8f8909cdb9f1b237786c09a810e24ee5e15ef17019f7cecb207ce205b9b5fcce"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ad47b095f0bdc5585bced35bd088cbfe4177236c7df9984b3cc46b391cc60627"}, + {file = "wrapt-1.17.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:948a9bd0fb2c5120457b07e59c8d7210cbc8703243225dbd78f4dfc13c8d2d1f"}, + {file = "wrapt-1.17.0-cp38-cp38-win32.whl", hash = "sha256:5ae271862b2142f4bc687bdbfcc942e2473a89999a54231aa1c2c676e28f29ea"}, + {file = "wrapt-1.17.0-cp38-cp38-win_amd64.whl", hash = "sha256:f335579a1b485c834849e9075191c9898e0731af45705c2ebf70e0cd5d58beed"}, + {file = "wrapt-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:d751300b94e35b6016d4b1e7d0e7bbc3b5e1751e2405ef908316c2a9024008a1"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7264cbb4a18dc4acfd73b63e4bcfec9c9802614572025bdd44d0721983fc1d9c"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33539c6f5b96cf0b1105a0ff4cf5db9332e773bb521cc804a90e58dc49b10578"}, + {file = "wrapt-1.17.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c30970bdee1cad6a8da2044febd824ef6dc4cc0b19e39af3085c763fdec7de33"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:bc7f729a72b16ee21795a943f85c6244971724819819a41ddbaeb691b2dd85ad"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:6ff02a91c4fc9b6a94e1c9c20f62ea06a7e375f42fe57587f004d1078ac86ca9"}, + {file = "wrapt-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2dfb7cff84e72e7bf975b06b4989477873dcf160b2fd89959c629535df53d4e0"}, + {file = "wrapt-1.17.0-cp39-cp39-win32.whl", hash = "sha256:2399408ac33ffd5b200480ee858baa58d77dd30e0dd0cab6a8a9547135f30a88"}, + {file = "wrapt-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:4f763a29ee6a20c529496a20a7bcb16a73de27f5da6a843249c7047daf135977"}, + {file = "wrapt-1.17.0-py3-none-any.whl", hash = "sha256:d2c63b93548eda58abf5188e505ffed0229bf675f7c3090f8e36ad55b8cbc371"}, + {file = "wrapt-1.17.0.tar.gz", hash = "sha256:16187aa2317c731170a88ef35e8937ae0f533c402872c1ee5e6d079fcf320801"}, ] [[package]] From b62d9ddf5681cde39726c2794b14843bb046b67d Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 13:19:46 +0800 Subject: [PATCH 26/41] fix: Return http health checking --- backend/chatsky_ui/services/process.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 973f1992..765e069f 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -175,17 +175,17 @@ async def check_telegram_readiness(stream, name): return True return False - # async with AsyncClient() as client: - # try: - # response = await client.get( - # f"http://localhost:{HTTP_INTERFACE_PORT}/health", - # ) - # return response.json()["status"] == "ok" - # except Exception as e: - # self.logger.info( - # f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " - # f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" - # ) + async with AsyncClient() as client: + try: + response = await client.get( + f"http://localhost:{HTTP_INTERFACE_PORT}/health", + ) + return response.json()["status"] == "ok" + except Exception as e: + self.logger.info( + f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " + f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" + ) done, pending = await asyncio.wait( [ From 11b5101b430a2057e180f6ce42b140abbad95c05 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 18:41:56 +0800 Subject: [PATCH 27/41] fix: Set a logger for service_replacer --- .../service_replacer.py | 23 +++++++++++++------ backend/chatsky_ui/services/process.py | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index 2253fd2d..4af3dd61 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -2,15 +2,23 @@ from ast import NodeTransformer from typing import Dict, List from pathlib import Path - +import logging from chatsky_ui.core.logger_config import get_logger -logger = get_logger(__name__) - class ServiceReplacer(NodeTransformer): def __init__(self, new_services: List[str]): self.new_services_classes = self._get_classes_def(new_services) + self._logger = None + + @property + def logger(self): + if self._logger is None: + raise ValueError("Logger has not been configured. Call set_logger() first.") + return self._logger + + def set_logger(self): + self._logger = get_logger(__name__) def _get_classes_def(self, services_code: List[str]) -> Dict[str, ast.ClassDef]: parsed_codes = [ast.parse(service_code) for service_code in services_code] @@ -24,11 +32,11 @@ def _extract_class_defs(self, parsed_code: ast.Module, service_code: str): if isinstance(node, ast.ClassDef): classes[node.name] = node else: - logger.error("No class definition found in new_service: %s", service_code) + self.logger.error("No class definition found in new_service: %s", service_code) return classes def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: - logger.debug("Visiting class '%s' and comparing with: %s", node.name, self.new_services_classes.keys()) + self.logger.debug("Visiting class '%s' and comparing with: %s", node.name, self.new_services_classes.keys()) if node.name in self.new_services_classes: return self._get_class_def(node) return node @@ -36,7 +44,7 @@ def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: def _get_class_def(self, node: ast.ClassDef) -> ast.ClassDef: service = self.new_services_classes[node.name] del self.new_services_classes[node.name] - logger.info("Updating class '%s'", node.name) + self.logger.info("Updating class '%s'", node.name) return service def generic_visit(self, node: ast.AST): @@ -46,7 +54,7 @@ def generic_visit(self, node: ast.AST): return node def _append_new_services(self, node: ast.Module): - logger.info("Services not found, appending new services: %s", list(self.new_services_classes.keys())) + self.logger.info("Services not found, appending new services: %s", list(self.new_services_classes.keys())) for _, service in self.new_services_classes.items(): node.body.append(service) @@ -56,6 +64,7 @@ def store_custom_service(services_path: Path, services: List[str]): conditions_tree = ast.parse(file.read()) replacer = ServiceReplacer(services) + replacer.set_logger() replacer.visit(conditions_tree) with open(services_path, "w") as file: diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 765e069f..93ef839e 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -183,7 +183,7 @@ async def check_telegram_readiness(stream, name): return response.json()["status"] == "ok" except Exception as e: self.logger.info( - f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}'. " + f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}' yet. " f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" ) From c434d36680689b0c1ad4ce5b3f9958cb73b8defb Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 19:06:39 +0800 Subject: [PATCH 28/41] chore: Clean old config refreshing --- backend/chatsky_ui/cli.py | 2 -- backend/chatsky_ui/core/config.py | 40 ++++++++---------------- backend/chatsky_ui/core/logger_config.py | 12 ++----- backend/chatsky_ui/main.py | 5 --- 4 files changed, 15 insertions(+), 44 deletions(-) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 65011566..895d77aa 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -181,8 +181,6 @@ def run_app( conf_reload=str(conf_reload).lower() in ["true", "yes", "t", "y", "1"], work_directory=project_dir, ) - if conf_reload: - settings.save_config() # this is for the sake of maintaining the state of the settings app_runner.set_settings(settings) app_runner.run() diff --git a/backend/chatsky_ui/core/config.py b/backend/chatsky_ui/core/config.py index b1daeb24..84f07ae0 100644 --- a/backend/chatsky_ui/core/config.py +++ b/backend/chatsky_ui/core/config.py @@ -3,8 +3,19 @@ import uvicorn from dotenv import load_dotenv -from omegaconf import DictConfig, OmegaConf +import logging +from typing import Dict + +LOG_LEVELS: Dict[str, int] = { + "critical": logging.CRITICAL, + "error": logging.ERROR, + "warning": logging.WARNING, + "info": logging.INFO, + "debug": logging.DEBUG, +} + +logging.basicConfig(level=LOG_LEVELS[os.getenv("LOG_LEVEL", "info")]) load_dotenv() @@ -38,6 +49,7 @@ def set_config(self, **kwargs): setattr(self, key, value) if "work_directory" in kwargs: + logging.debug("Setting work directory to %s", self.work_directory) self._set_user_proj_paths() def _set_user_proj_paths(self): @@ -53,32 +65,6 @@ def _set_user_proj_paths(self): self.responses_path = self.custom_dir / "responses.py" self.scripts_dir = self.work_directory / "bot/scripts" - def save_config(self): - if not self.temp_conf.exists(): - self.temp_conf.touch() - OmegaConf.save( - OmegaConf.create( - { - "work_directory": str(self.work_directory), - "host": self.host, - "port": self.port, - "log_level": self.log_level, - "conf_reload": self.conf_reload, - } - ), # type: ignore - self.temp_conf, - ) - - def _load_temp_config(self) -> DictConfig: - if not self.temp_conf.exists(): - raise FileNotFoundError(f"{self.temp_conf} not found.") - - return OmegaConf.load(self.temp_conf) # type: ignore - - def refresh_work_dir(self): - config = self._load_temp_config() - self.set_config(**config) - class AppRunner: def __init__(self): diff --git a/backend/chatsky_ui/core/logger_config.py b/backend/chatsky_ui/core/logger_config.py index 8fd0f345..c23ae07b 100644 --- a/backend/chatsky_ui/core/logger_config.py +++ b/backend/chatsky_ui/core/logger_config.py @@ -1,17 +1,9 @@ import logging from datetime import datetime from pathlib import Path -from typing import Dict, Literal, Optional +from typing import Literal, Optional -from chatsky_ui.core.config import settings - -LOG_LEVELS: Dict[str, int] = { - "critical": logging.CRITICAL, - "error": logging.ERROR, - "warning": logging.WARNING, - "info": logging.INFO, - "debug": logging.DEBUG, -} +from chatsky_ui.core.config import settings, LOG_LEVELS def setup_logging(log_type: Literal["builds", "runs"], id_: int, timestamp: datetime) -> Path: diff --git a/backend/chatsky_ui/main.py b/backend/chatsky_ui/main.py index 49a0f868..17493ed6 100644 --- a/backend/chatsky_ui/main.py +++ b/backend/chatsky_ui/main.py @@ -11,13 +11,8 @@ @asynccontextmanager async def lifespan(app: FastAPI): - if settings.temp_conf.exists(): - settings.refresh_work_dir() - yield - # settings.temp_conf.unlink(missing_ok=True) - app = FastAPI(title="DF Designer", version=__version__, lifespan=lifespan) From 221a2ff109289765507e463b24133b284da0e197 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 19:47:22 +0800 Subject: [PATCH 29/41] fix: Save script in periodic-check& separate is_alive --- backend/chatsky_ui/services/process.py | 101 ++++++++++++++----------- 1 file changed, 55 insertions(+), 46 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index 93ef839e..c37f42a0 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -163,47 +163,6 @@ async def stop(self) -> None: self.logger.error("Process '%s' not found. It may have already exited.", self.id) raise ProcessLookupError from exc - async def is_alive(self) -> bool: - """Checks if the process is alive by writing to stdin andreading its stdout.""" - async def check_telegram_readiness(stream, name): - async for line in stream: - decoded_line = line.decode().strip() - self.logger.info(f"[{name}] {decoded_line}") - - if "telegram.ext.Application:Application started" in decoded_line: - self.logger.info("The application is ready for use!") - return True - return False - - async with AsyncClient() as client: - try: - response = await client.get( - f"http://localhost:{HTTP_INTERFACE_PORT}/health", - ) - return response.json()["status"] == "ok" - except Exception as e: - self.logger.info( - f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}' yet. " - f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" - ) - - done, pending = await asyncio.wait( - [ - asyncio.create_task(check_telegram_readiness(self.process.stdout, "STDOUT")), - asyncio.create_task(check_telegram_readiness(self.process.stderr, "STDERR")), - ], - return_when=asyncio.FIRST_COMPLETED, - timeout=PING_PONG_TIMEOUT, - ) - - for task in pending: - task.cancel() - - for task in done: - result = task.result() - if result: - return result - def add_new_conf(self, conf: list, params: dict) -> list: #TODO: rename conf everywhere to metadata/meta for run in conf: if run.id == params["id"]: # type: ignore @@ -250,6 +209,49 @@ async def update_db_info(self) -> None: break await write_conf(builds_conf, settings.builds_path) + + async def is_alive(self) -> bool: + """Checks if the process is alive by writing to stdin andreading its stdout.""" + async def check_telegram_readiness(stream, name): + async for line in stream: + decoded_line = line.decode().strip() + self.logger.info(f"[{name}] {decoded_line}") + + if "telegram.ext.Application:Application started" in decoded_line: + self.logger.info("The application is ready for use!") + return True + return False + + async with AsyncClient() as client: + try: + response = await client.get( + f"http://localhost:{HTTP_INTERFACE_PORT}/health", + ) + return response.json()["status"] == "ok" + except Exception as e: + self.logger.info( + f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}' yet. " + f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" + ) + + done, pending = await asyncio.wait( + [ + asyncio.create_task(check_telegram_readiness(self.process.stdout, "STDOUT")), + asyncio.create_task(check_telegram_readiness(self.process.stderr, "STDERR")), + ], + return_when=asyncio.FIRST_COMPLETED, + timeout=PING_PONG_TIMEOUT, + ) + + for task in pending: + task.cancel() + + for task in done: + result = task.result() + if result: + return result + + return False class BuildProcess(Process): @@ -280,8 +282,15 @@ def save_built_script_to_git(self, id_: int) -> None: bot_repo = get_repo(settings.custom_dir.parent) save_built_script_to_git(id_, bot_repo) - async def check_status(self) -> Status: - status = await super().check_status() - if status not in [Status.NULL, Status.RUNNING, Status.ALIVE]: - # Save the project anyway to keep a gradual number of builds - self.save_built_script_to_git(self.id) + async def periodically_check_status(self) -> None: + """Periodically checks the process status and updates the database.""" + while True: + await self.update_db_info() # check status and update db + self.logger.info("Status of process '%s': %s", self.id, self.status) + if self.status in [Status.NULL, Status.STOPPED, Status.COMPLETED, Status.FAILED]: + self.save_built_script_to_git(self.id) + break + await asyncio.sleep(2) # TODO: ?sleep time shouldn't be constant + + async def is_alive(self) -> bool: + return False From 077e7584e956cc15dd1a867c649b42c3cf08439c Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Fri, 29 Nov 2024 21:22:22 +0800 Subject: [PATCH 30/41] fix: Return config reload refreshing feature --- backend/chatsky_ui/cli.py | 2 ++ backend/chatsky_ui/core/config.py | 27 +++++++++++++++++++++++++++ backend/chatsky_ui/main.py | 2 ++ 3 files changed, 31 insertions(+) diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 895d77aa..65011566 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -181,6 +181,8 @@ def run_app( conf_reload=str(conf_reload).lower() in ["true", "yes", "t", "y", "1"], work_directory=project_dir, ) + if conf_reload: + settings.save_config() # this is for the sake of maintaining the state of the settings app_runner.set_settings(settings) app_runner.run() diff --git a/backend/chatsky_ui/core/config.py b/backend/chatsky_ui/core/config.py index 84f07ae0..76321f5c 100644 --- a/backend/chatsky_ui/core/config.py +++ b/backend/chatsky_ui/core/config.py @@ -5,6 +5,7 @@ from dotenv import load_dotenv import logging from typing import Dict +from omegaconf import DictConfig, OmegaConf LOG_LEVELS: Dict[str, int] = { @@ -65,6 +66,32 @@ def _set_user_proj_paths(self): self.responses_path = self.custom_dir / "responses.py" self.scripts_dir = self.work_directory / "bot/scripts" + def save_config(self): + if not self.temp_conf.exists(): + self.temp_conf.touch() + OmegaConf.save( + OmegaConf.create( + { + "work_directory": str(self.work_directory), + "host": self.host, + "port": self.port, + "log_level": self.log_level, + "conf_reload": self.conf_reload, + } + ), # type: ignore + self.temp_conf, + ) + + def _load_temp_config(self) -> DictConfig: + if not self.temp_conf.exists(): + raise FileNotFoundError(f"{self.temp_conf} not found.") + + return OmegaConf.load(self.temp_conf) # type: ignore + + def refresh_work_dir(self): + config = self._load_temp_config() + self.set_config(**config) + class AppRunner: def __init__(self): diff --git a/backend/chatsky_ui/main.py b/backend/chatsky_ui/main.py index 17493ed6..706cd5a0 100644 --- a/backend/chatsky_ui/main.py +++ b/backend/chatsky_ui/main.py @@ -11,6 +11,8 @@ @asynccontextmanager async def lifespan(app: FastAPI): + if settings.temp_conf.exists(): + settings.refresh_work_dir() yield From c1f3696a00c86b41be3c1ae1e0692da09f019742 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 2 Dec 2024 16:51:28 +0800 Subject: [PATCH 31/41] fix: Terminate a group process with its children --- backend/chatsky_ui/services/process.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index c37f42a0..c3b4a821 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -7,6 +7,7 @@ import asyncio import logging import os +import signal from abc import ABC, abstractmethod from datetime import datetime from pathlib import Path @@ -49,6 +50,7 @@ async def start(self, cmd_to_run: str) -> None: stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE, stdin=asyncio.subprocess.PIPE, + preexec_fn=os.setsid, ) async def get_full_info(self, attributes: list) -> Dict[str, Any]: @@ -148,19 +150,17 @@ async def stop(self) -> None: self.logger.error("Cannot stop a process '%s' that has not started yet.", self.id) raise RuntimeError try: - self.logger.debug("Terminating process '%s'", self.id) - self.process.terminate() + self.logger.debug("Terminating process '%s' with group process pid of '%s'", self.id, self.process.pid) + os.killpg(os.getpgid(self.process.pid), signal.SIGTERM) try: await asyncio.wait_for(self.process.wait(), timeout=GRACEFUL_TERMINATION_TIMEOUT) self.logger.debug("Process '%s' was gracefully terminated.", self.id) except asyncio.TimeoutError: - self.process.kill() - await self.process.wait() + os.killpg(os.getpgid(self.process.pid), signal.SIGKILL) self.logger.debug("Process '%s' was forcefully killed.", self.id) self.logger.debug("Process returencode '%s' ", self.process.returncode) - except ProcessLookupError as exc: - self.logger.error("Process '%s' not found. It may have already exited.", self.id) + self.logger.error("Process group '%s' not found. It may have already exited.", self.id) raise ProcessLookupError from exc def add_new_conf(self, conf: list, params: dict) -> list: #TODO: rename conf everywhere to metadata/meta From 50eb3810394c1b4141f387f93d6bf107d0e258f2 Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Mon, 2 Dec 2024 15:44:11 +0300 Subject: [PATCH 32/41] websocket removed --- frontend/src/api/bot.ts | 27 +++++++ frontend/src/api/flows.ts | 33 ++++---- frontend/src/components/chat/Chat.tsx | 104 +++++++++++--------------- frontend/src/contexts/runContext.tsx | 8 +- 4 files changed, 98 insertions(+), 74 deletions(-) diff --git a/frontend/src/api/bot.ts b/frontend/src/api/bot.ts index 2129471b..ad325eac 100644 --- a/frontend/src/api/bot.ts +++ b/frontend/src/api/bot.ts @@ -96,6 +96,14 @@ type buildStatusResponseType = { status: buildApiStatusType } +type botMessage = { + user_id: string + response: { + text: string + [key: string]: unknown + } +} + export const build_start = async (preset?: buildPresetType) => { try { const { data }: { data: buildStartResponseType } = await $v1.post("/bot/build/start", preset) @@ -199,3 +207,22 @@ export const run_status = async (run_id: number) => { throw error } } + +export const send_message = async (user_message: string) => { + try { + const { data }: { data: botMessage } = await $v1.post( + "/bot/chat", + {}, + { + params: { + user_id: "any", + user_message, + }, + } + ) + return data + } catch (error) { + console.log(error) + throw error + } +} diff --git a/frontend/src/api/flows.ts b/frontend/src/api/flows.ts index 314014e8..106537fb 100644 --- a/frontend/src/api/flows.ts +++ b/frontend/src/api/flows.ts @@ -4,27 +4,34 @@ import { FlowType } from "../types/FlowTypes" import { ParsedSlot } from "../utils" import { GetFlowsResponseType, SaveFlowsResponseType } from "./flows.types" - - export const get_flows = async (): Promise => { return (await $v1.get("/flows")).data } -export const save_flows = async (flows: FlowType[], _interface: interfaceType, slots?: Record | null): Promise => { +export const save_flows = async ( + flows: FlowType[], + _interface: interfaceType, + slots?: Record | null +): Promise => { // const hasValidSlots = slots && Object.values(slots).some(slot => Object.keys(slot).length > 0); - const _i = _interface.interface === "tg" ? { - telegram: { - token: _interface.token - } - } : { - cli: {} - } + const _i = + _interface.interface === "tg" + ? { + telegram: { + token: _interface.token, + }, + } + : { + http: {}, + } + const json = { flows, slots: slots ?? {}, interface: { - ..._i - } + ..._i, + }, } + return (await $v1.post("/flows", json)).data -} \ No newline at end of file +} diff --git a/frontend/src/components/chat/Chat.tsx b/frontend/src/components/chat/Chat.tsx index fa6de484..66a60424 100644 --- a/frontend/src/components/chat/Chat.tsx +++ b/frontend/src/components/chat/Chat.tsx @@ -12,12 +12,12 @@ import { DEV } from "../../env.consts" import ChatIcon from "../../icons/buildmenu/ChatIcon" import { parseSearchParams } from "../../utils" import EmojiPicker, { EmojiType } from "./EmojiPicker" +import { send_message } from "@/api/bot" const Chat = memo(() => { const { chat, setChat, messages, setMessages } = useContext(chatContext) const { run, runStatus } = useContext(runContext) const [searchParams, setSearchParams] = useSearchParams() - const ws = useRef(null) const { setMouseOnPane } = useContext(workspaceContext) const { notification: n } = useContext(NotificationsContext) @@ -46,33 +46,35 @@ const Chat = memo(() => { const [messageValue, setMessageValue] = useState("") - const handleMessage = () => { - if (messageValue) { - if (ws.current && ws.current.readyState === 1) { - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore - ws.current.send(messageValue) - setMessages([ - ...messages, - { - message: messageValue, - type: "user", - }, - ]) - setMessageValue("") - setIsEmoji(false) - } else { - setMessages([ - ...messages, - { - message: "WS connection is not opened! Try to start any run!", - type: "system", - }, - ]) - setMessageValue("") - setIsEmoji(false) - } + const handleMessage = async () => { + setMessageValue("") + setIsEmoji(false) + + if (runStatus !== "alive" || !run) { + setMessages([ + ...messages, + { + message: "Chat was not connected! Try to start any run!", + type: "system", + }, + ]) + setMessageValue("") + setIsEmoji(false) + return } + + setMessages([ + ...messages, + { + message: messageValue, + type: "user", + }, + ]) + + const { response } = await send_message(messageValue) + setTimeout(() => { + setMessages((prev) => [...prev, { message: response.text, type: "bot" }]) + }, 500) } useEffect(() => { @@ -116,42 +118,19 @@ const Chat = memo(() => { }, }) - useEffect(() => { - if (runStatus === "alive" && run) { - const socket = new WebSocket( - `ws://${DEV ? "localhost:8000" : window.location.host}/api/v1/bot/run/connect?run_id=${run.id}` - ) - socket.onopen = () => { - n.add({ message: "Chat was successfully connected!", title: "Success", type: "success" }) - } - socket.onmessage = (event: MessageEvent) => { - console.log(event) - if (event.data) { - const data = event.data - setTimeout(() => { - setMessages((prev) => [...prev, { message: data, type: "bot" }]) - }, 500) - } - socket.onclose = (event) => { - socket.close() - console.log("websocket closed", event) - } - } - ws.current = socket - } - return () => { - ws.current?.close() + if (runStatus === "alive") { + setMessages((prev) => prev.filter((message) => message.type != "system")) } - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [run, runStatus]) + }, [runStatus, setMessages]) return (
+ }} + >
@@ -166,7 +145,8 @@ const Chat = memo(() => { size='sm' onClick={() => { setMessages([]) - }}> + }} + > @@ -180,14 +160,16 @@ const Chat = memo(() => { }} size='sm' variant='light' - isIconOnly> + isIconOnly + >
+ className='h-[60vh] bg-chat border-b border-border px-2 py-2 overflow-y-scroll scrollbar-hide flex flex-col gap-2' + > {messagesT((style, m) => ( { key={m.message + m.type + Math.random()} className={`flex items-center ${ m.type === "user" ? "justify-end" : "justify-start" - } `}> + } `} + >
+ }} + > {m.message}
diff --git a/frontend/src/contexts/runContext.tsx b/frontend/src/contexts/runContext.tsx index 8d817a4d..2d68864f 100644 --- a/frontend/src/contexts/runContext.tsx +++ b/frontend/src/contexts/runContext.tsx @@ -121,6 +121,11 @@ export const RunProvider = ({ children }: { children: React.ReactNode }) => { flag = false setRunPending(false) setRunStatus("alive") + n.add({ + message: "", + title: "Run started!", + type: "success", + }) } if (status === "failed") { flag = false @@ -186,7 +191,8 @@ export const RunProvider = ({ children }: { children: React.ReactNode }) => { setRuns, setRunStatus, setRunsHandler, - }}> + }} + > {children} ) From afb79a89c7d8012c028dc8c94fe32c44036f292e Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 2 Dec 2024 23:45:14 +0800 Subject: [PATCH 33/41] fix: Get env vars after reloading if any --- backend/chatsky_ui/schemas/front_graph_components/interface.py | 1 + 1 file changed, 1 insertion(+) diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index a11a7b57..26ae339d 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -28,6 +28,7 @@ def check_one_not_none(cls, values): @model_validator(mode="after") def check_telegram_token(cls, values): + load_dotenv(os.path.join(settings.work_directory, ".env")) tg_bot_token = os.getenv("TG_BOT_TOKEN") if values.telegram is not None and not tg_bot_token: raise ValueError("Telegram token must be provided.") From b8e9ebac74783e3fc3de7881770148aef2d60310 Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Mon, 2 Dec 2024 18:49:30 +0300 Subject: [PATCH 34/41] fix responses and conditions --- frontend/src/consts.tsx | 2 +- frontend/src/modals/ConditionModal/ConditionModal.tsx | 2 +- frontend/src/modals/ConditionModal/editorOptions.tsx | 2 +- frontend/src/modals/ResponseModal/ResponseModal.tsx | 4 +++- frontend/src/utils.ts | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/frontend/src/consts.tsx b/frontend/src/consts.tsx index 2fd68256..22b828b7 100644 --- a/frontend/src/consts.tsx +++ b/frontend/src/consts.tsx @@ -124,7 +124,7 @@ export const NODES = { global_conditions: [], local_conditions: [], response: { - name: "default_response", + name: "DefaultResponse", type: "text", data: [{ text: "I am a bot and here is my quote ", priority: 1 }], }, diff --git a/frontend/src/modals/ConditionModal/ConditionModal.tsx b/frontend/src/modals/ConditionModal/ConditionModal.tsx index 119cd9ac..7c234c29 100644 --- a/frontend/src/modals/ConditionModal/ConditionModal.tsx +++ b/frontend/src/modals/ConditionModal/ConditionModal.tsx @@ -400,7 +400,7 @@ const ConditionModal = ({ labelPlacement='outside' placeholder="Enter condition's name here" value={currentCondition.name} - onChange={(e) => setCurrentCondition({ ...currentCondition, name: e.target.value })} + onChange={(e) => setCurrentCondition({ ...currentCondition, name: e.target.value.replace(/\s/g, '') })} /> class ${name}(${baseType}):` } const returnType = type === "condition" ? "bool" : "Message" - return ` def call(self, ctx: Context) -> ${returnType}:` + return ` async def call(self, ctx: Context) -> ${returnType}:` } // Метод для обработки первой и второй строк diff --git a/frontend/src/modals/ResponseModal/ResponseModal.tsx b/frontend/src/modals/ResponseModal/ResponseModal.tsx index d2ab7e99..2e367aa4 100644 --- a/frontend/src/modals/ResponseModal/ResponseModal.tsx +++ b/frontend/src/modals/ResponseModal/ResponseModal.tsx @@ -173,7 +173,9 @@ const ResponseModal = ({ placeholder="Enter response's name here" value={currentResponse.name} isRequired - onChange={(e) => setCurrentResponse({ ...currentResponse, name: e.target.value })} + onChange={(e) => + setCurrentResponse({ ...currentResponse, name: e.target.value.replace(/\s/g, "") }) + } />
{bodyItems[selected]}
diff --git a/frontend/src/utils.ts b/frontend/src/utils.ts index 813fca6c..766ddc29 100644 --- a/frontend/src/utils.ts +++ b/frontend/src/utils.ts @@ -55,7 +55,7 @@ export const parseSearchParams = ( export const generateNewConditionBase = (): conditionType => { return { id: "condition_" + v4(), - name: "new_cnd", + name: "NewCnd", type: "python", data: { priority: 1, From e5aedc377409da2ec968dd8a2ac82f9ae0768808 Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Mon, 2 Dec 2024 18:54:33 +0300 Subject: [PATCH 35/41] token sending added --- frontend/src/api/flows.ts | 21 ++++++++++++++++++--- frontend/src/modals/LaunchModal.tsx | 4 +++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/frontend/src/api/flows.ts b/frontend/src/api/flows.ts index 106537fb..b279cf95 100644 --- a/frontend/src/api/flows.ts +++ b/frontend/src/api/flows.ts @@ -17,9 +17,7 @@ export const save_flows = async ( const _i = _interface.interface === "tg" ? { - telegram: { - token: _interface.token, - }, + telegram: {}, } : { http: {}, @@ -35,3 +33,20 @@ export const save_flows = async ( return (await $v1.post("/flows", json)).data } + +export const set_tg_token = async (token: string) => { + try { + await $v1.post( + "/flows/tg_token", + {}, + { + params: { + token, + }, + } + ) + } catch (error) { + console.log(error) + throw error + } +} diff --git a/frontend/src/modals/LaunchModal.tsx b/frontend/src/modals/LaunchModal.tsx index 22951c0b..559d7ec3 100644 --- a/frontend/src/modals/LaunchModal.tsx +++ b/frontend/src/modals/LaunchModal.tsx @@ -6,6 +6,7 @@ import DefInput from "@/UI/Input/DefInput" import { Button } from "@nextui-org/react" import React, { useContext, useState } from "react" import { CustomModalProps, Modal, ModalBody, ModalFooter, ModalHeader } from "./ModalComponents" +import { set_tg_token } from "@/api/flows" type LaunchModalProps = CustomModalProps & { title?: React.ReactNode @@ -33,8 +34,9 @@ const LaunchModal = ({ const onActionHandler = async () => { try { - saveFlows(flows, { interface: "tg", token }) onCloseHandler() + await saveFlows(flows, { interface: "tg" }) + await set_tg_token(token) await buildStart({ wait_time: 0, end_status: "success" }) await runStart({ end_status: "success", wait_time: 0 }) } catch (error) { From 7c1a12c7e200cbd56374f86aed8969166b2fba0c Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Mon, 2 Dec 2024 19:38:14 +0300 Subject: [PATCH 36/41] rename repeat to current --- frontend/src/consts.tsx | 2 +- frontend/src/types/ConditionTypes.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/consts.tsx b/frontend/src/consts.tsx index 22b828b7..20fda0a5 100644 --- a/frontend/src/consts.tsx +++ b/frontend/src/consts.tsx @@ -174,7 +174,7 @@ export const CONDITION_LABELS: { manual: "manual", forward: "forward", backward: "backward", - repeat: "repeat", + current: "current", fallback: "fallback", start: "start", previous: "previous", diff --git a/frontend/src/types/ConditionTypes.ts b/frontend/src/types/ConditionTypes.ts index 7e774527..fe429d05 100644 --- a/frontend/src/types/ConditionTypes.ts +++ b/frontend/src/types/ConditionTypes.ts @@ -33,7 +33,7 @@ export type conditionLabelType = | "manual" | "forward" | "backward" - | "repeat" + | "current" | "fallback" | "start" | "previous" From 9491d2b57c514a012df781e4cc8e6394023bc42b Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Tue, 3 Dec 2024 12:52:01 +0300 Subject: [PATCH 37/41] chore: update dependencies --- backend/poetry.lock | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index f35c43b7..ff1e8617 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.7.1 and should not be changed by hand. [[package]] name = "aiofiles" @@ -13,13 +13,13 @@ files = [ [[package]] name = "aiolimiter" -version = "1.1.0" +version = "1.1.1" description = "asyncio rate limiter, a leaky bucket implementation" optional = false -python-versions = ">=3.7,<4.0" +python-versions = "<4.0,>=3.8" files = [ - {file = "aiolimiter-1.1.0-py3-none-any.whl", hash = "sha256:0b4997961fc58b8df40279e739f9cf0d3e255e63e9a44f64df567a8c17241e24"}, - {file = "aiolimiter-1.1.0.tar.gz", hash = "sha256:461cf02f82a29347340d031626c92853645c099cb5ff85577b831a7bd21132b5"}, + {file = "aiolimiter-1.1.1-py3-none-any.whl", hash = "sha256:bf23dafbd1370e0816792fbcfb8fb95d5138c26e05f839fe058f5440bea006f5"}, + {file = "aiolimiter-1.1.1.tar.gz", hash = "sha256:4b5740c96ecf022d978379130514a26c18001e7450ba38adf19515cd0970f68f"}, ] [[package]] @@ -449,7 +449,7 @@ ydb = ["six", "ydb"] type = "git" url = "https://github.com/deeppavlov/chatsky.git" reference = "feat/add-docker-image" -resolved_reference = "584d06b233c0ebf068533a6afb7103d26eb73dfe" +resolved_reference = "7e8f2615337d2308b71e256f469fc58ce52f6156" [[package]] name = "click" @@ -1530,13 +1530,13 @@ unidecode = ["Unidecode (>=1.1.1)"] [[package]] name = "python-telegram-bot" -version = "21.7" +version = "21.8" description = "We have made you a wrapper you can't refuse" optional = false python-versions = ">=3.9" files = [ - {file = "python_telegram_bot-21.7-py3-none-any.whl", hash = "sha256:aff1d7245f1b0d4d12d41c9acff74e86d7100713c2204cd02ff17f8d80d18846"}, - {file = "python_telegram_bot-21.7.tar.gz", hash = "sha256:bc8537b77ae02531fc2ad440caafc023fd13f13cf19e592dfa1a9ff84988a012"}, + {file = "python_telegram_bot-21.8-py3-none-any.whl", hash = "sha256:2fea8e65d97e593f47666e7de81fb15bd517100504e98ca7cb399ee6ce4f3838"}, + {file = "python_telegram_bot-21.8.tar.gz", hash = "sha256:114437f194e32eee0651f25fb1ab1664b605e877ca33adf58547a599afe73b72"}, ] [package.dependencies] From dc2952981a21b450fb092b22eb6d92c099aff009 Mon Sep 17 00:00:00 2001 From: Artem Marin Date: Tue, 3 Dec 2024 13:24:38 +0300 Subject: [PATCH 38/41] fix: fixed chat functionality --- frontend/src/api/bot.ts | 4 ++-- frontend/src/components/chat/Chat.tsx | 9 +++++---- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/frontend/src/api/bot.ts b/frontend/src/api/bot.ts index ad325eac..f0514769 100644 --- a/frontend/src/api/bot.ts +++ b/frontend/src/api/bot.ts @@ -208,14 +208,14 @@ export const run_status = async (run_id: number) => { } } -export const send_message = async (user_message: string) => { +export const send_message = async (user_id: number, user_message: string) => { try { const { data }: { data: botMessage } = await $v1.post( "/bot/chat", {}, { params: { - user_id: "any", + user_id, user_message, }, } diff --git a/frontend/src/components/chat/Chat.tsx b/frontend/src/components/chat/Chat.tsx index 66a60424..7d8d85ee 100644 --- a/frontend/src/components/chat/Chat.tsx +++ b/frontend/src/components/chat/Chat.tsx @@ -5,10 +5,8 @@ import { Paperclip, RefreshCcw, Send, Smile, X } from "lucide-react" import { memo, useContext, useEffect, useRef, useState } from "react" import { useSearchParams } from "react-router-dom" import { chatContext } from "../../contexts/chatContext" -import { NotificationsContext } from "../../contexts/notificationsContext" import { runContext } from "../../contexts/runContext" import { workspaceContext } from "../../contexts/workspaceContext" -import { DEV } from "../../env.consts" import ChatIcon from "../../icons/buildmenu/ChatIcon" import { parseSearchParams } from "../../utils" import EmojiPicker, { EmojiType } from "./EmojiPicker" @@ -19,7 +17,6 @@ const Chat = memo(() => { const { run, runStatus } = useContext(runContext) const [searchParams, setSearchParams] = useSearchParams() const { setMouseOnPane } = useContext(workspaceContext) - const { notification: n } = useContext(NotificationsContext) const [isEmoji, setIsEmoji] = useState(false) @@ -71,7 +68,7 @@ const Chat = memo(() => { }, ]) - const { response } = await send_message(messageValue) + const { response } = await send_message(0, messageValue) // user_id is hardcoded; it will need to be fixed later setTimeout(() => { setMessages((prev) => [...prev, { message: response.text, type: "bot" }]) }, 500) @@ -124,6 +121,10 @@ const Chat = memo(() => { } }, [runStatus, setMessages]) + useEffect(() => { + setMessages([]) + }, [run?.id, setMessages]) + return (
Date: Mon, 16 Dec 2024 18:26:18 +0800 Subject: [PATCH 39/41] Merge branch 'dev' into fix/sync-with-backend --- .github/workflows/backend_check.yml | 10 +- README.md | 4 +- .../chatsky_ui/api/api_v1/endpoints/bot.py | 13 ++- .../api/api_v1/endpoints/chatsky_services.py | 2 +- .../chatsky_ui/api/api_v1/endpoints/flows.py | 13 ++- backend/chatsky_ui/api/deps.py | 1 - backend/chatsky_ui/cli.py | 16 +-- backend/chatsky_ui/core/config.py | 9 +- backend/chatsky_ui/core/logger_config.py | 2 +- backend/chatsky_ui/main.py | 13 +++ .../front_graph_components/interface.py | 17 ++-- .../schemas/front_graph_components/node.py | 3 +- .../services/json_converter/base_converter.py | 10 ++ .../services/json_converter/consts.py | 3 + .../services/json_converter/flow_converter.py | 72 ++++++++++++++ .../json_converter/interface_converter.py | 15 +++ .../condition_converter.py | 57 +++++++++++ .../response_converter.py | 42 ++++++++ .../service_replacer.py | 82 ++++++++++++++++ .../services/json_converter/node_converter.py | 84 ++++++++++++++++ .../json_converter/pipeline_converter.py | 48 +++++++++ .../json_converter/script_converter.py | 51 ++++++++++ .../json_converter/slots_converter.py | 75 ++++++++++++++ backend/chatsky_ui/services/process.py | 35 ++++--- .../chatsky_ui/services/process_manager.py | 16 +-- backend/chatsky_ui/tests/api/test_bot.py | 61 ++++-------- backend/chatsky_ui/tests/conftest.py | 56 +++++++---- .../chatsky_ui/tests/integration/test_bot.py | 97 +++++++++++++++++++ .../chatsky_ui/tests/services/test_process.py | 36 ++++--- .../tests/services/test_websocket_manager.py | 57 ----------- backend/chatsky_ui/tests/unit/conftest.py | 10 +- .../tests/unit/test_flow_converter.py | 19 ++-- .../tests/unit/test_logic_components.py | 16 +-- .../tests/unit/test_node_converer.py | 2 +- .../tests/unit/test_slots_converter.py | 6 +- backend/poetry.lock | 18 ++-- backend/pyproject.toml | 4 +- bin/add_ui_to_toml.sh | 7 -- 38 files changed, 829 insertions(+), 253 deletions(-) create mode 100644 backend/chatsky_ui/services/json_converter/base_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/consts.py create mode 100644 backend/chatsky_ui/services/json_converter/flow_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/interface_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/logic_component_converter/condition_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/logic_component_converter/response_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/logic_component_converter/service_replacer.py create mode 100644 backend/chatsky_ui/services/json_converter/node_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/pipeline_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/script_converter.py create mode 100644 backend/chatsky_ui/services/json_converter/slots_converter.py create mode 100644 backend/chatsky_ui/tests/integration/test_bot.py delete mode 100644 backend/chatsky_ui/tests/services/test_websocket_manager.py delete mode 100755 bin/add_ui_to_toml.sh diff --git a/.github/workflows/backend_check.yml b/.github/workflows/backend_check.yml index ce2b77ea..72c3e217 100644 --- a/.github/workflows/backend_check.yml +++ b/.github/workflows/backend_check.yml @@ -75,13 +75,9 @@ jobs: python -m poetry run chatsky.ui init --destination ../ --no-input --overwrite-if-exists working-directory: backend - - name: Install chatsky-ui into new project poetry environment - run: | - ../bin/add_ui_to_toml.sh - working-directory: my_project - - name: run tests run: | - python -m poetry install --no-root - python -m poetry run pytest ../backend/chatsky_ui/tests/ --verbose + poetry install --with dev -C ../backend + POETRY_ENV=$(poetry env info --path -C ../backend) + $POETRY_ENV/bin/pytest ../backend/chatsky_ui/tests/ --verbose working-directory: my_project diff --git a/README.md b/README.md index fce37cbc..c46a7b1c 100644 --- a/README.md +++ b/README.md @@ -1,9 +1,9 @@ # Quick Start ## System Requirements -Ensure you have Python version 3.8.1 or higher installed. +Ensure you have Python version 3.9 or higher installed (Excluding 3.9.7). ## Installation -To install the necessary package, run the following command: +To install the package and necessary dependencies, run the following command: ```bash pip install chatsky-ui ``` diff --git a/backend/chatsky_ui/api/api_v1/endpoints/bot.py b/backend/chatsky_ui/api/api_v1/endpoints/bot.py index 6485548d..24a9d451 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/bot.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/bot.py @@ -1,15 +1,14 @@ import asyncio from typing import Any, Dict, List, Optional, Union -from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, WebSocket, WebSocketException, status -from chatsky.messengers.http_interface import HTTP_INTERFACE_PORT +from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, status +from httpx import AsyncClient from chatsky_ui.api import deps +from chatsky_ui.core.config import settings from chatsky_ui.schemas.pagination import Pagination from chatsky_ui.schemas.preset import Preset -from chatsky_ui.schemas.process_status import Status from chatsky_ui.services.process_manager import BuildManager, ProcessManager, RunManager -from httpx import AsyncClient router = APIRouter() @@ -144,7 +143,7 @@ async def start_run( build_id: int, preset: Preset, background_tasks: BackgroundTasks, - run_manager: RunManager = Depends(deps.get_run_manager) + run_manager: RunManager = Depends(deps.get_run_manager), ) -> Dict[str, Union[str, int]]: """Starts a `run` process with the given preset. @@ -243,12 +242,12 @@ async def respond( async with AsyncClient() as client: try: response = await client.post( - f"http://localhost:{HTTP_INTERFACE_PORT}/chat", + f"http://localhost:{settings.chatsky_port}/chat", params={"user_id": user_id, "user_message": user_message}, ) return response.json() except Exception as e: raise HTTPException( status_code=status.HTTP_503_SERVICE_UNAVAILABLE, - detail=f"Please check that service's up and running on the port '{HTTP_INTERFACE_PORT}'.", + detail=f"Please check that service's up and running on the port '{settings.chatsky_port}'.", ) from e diff --git a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py index 42e55214..d5cb6d62 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/chatsky_services.py @@ -10,7 +10,7 @@ from chatsky_ui.clients.chatsky_client import get_chatsky_conditions from chatsky_ui.core.config import settings from chatsky_ui.schemas.code_snippet import CodeSnippet -from chatsky_ui.services.json_converter_new2.logic_component_converter.service_replacer import get_all_classes +from chatsky_ui.services.json_converter.logic_component_converter.service_replacer import get_all_classes from chatsky_ui.utils.ast_utils import get_imports_from_file router = APIRouter() diff --git a/backend/chatsky_ui/api/api_v1/endpoints/flows.py b/backend/chatsky_ui/api/api_v1/endpoints/flows.py index 490f099a..f54e7d01 100644 --- a/backend/chatsky_ui/api/api_v1/endpoints/flows.py +++ b/backend/chatsky_ui/api/api_v1/endpoints/flows.py @@ -1,16 +1,15 @@ -from typing import Dict, Union, Optional +from pathlib import Path +from typing import Dict, Optional, Union -from fastapi import APIRouter, status, HTTPException -from omegaconf import OmegaConf +from dotenv import set_key +from fastapi import APIRouter, HTTPException, status from git.exc import GitCommandError +from omegaconf import OmegaConf from chatsky_ui.core.config import settings +from chatsky_ui.core.logger_config import get_logger from chatsky_ui.db.base import read_conf, write_conf from chatsky_ui.utils.git_cmd import commit_changes, get_repo -from chatsky_ui.core.logger_config import get_logger -from pathlib import Path -from dotenv import set_key - router = APIRouter() diff --git a/backend/chatsky_ui/api/deps.py b/backend/chatsky_ui/api/deps.py index af10d17f..a63efa9f 100644 --- a/backend/chatsky_ui/api/deps.py +++ b/backend/chatsky_ui/api/deps.py @@ -1,6 +1,5 @@ from chatsky_ui.services.process_manager import BuildManager, RunManager - build_manager = BuildManager() diff --git a/backend/chatsky_ui/cli.py b/backend/chatsky_ui/cli.py index 65011566..1132118c 100644 --- a/backend/chatsky_ui/cli.py +++ b/backend/chatsky_ui/cli.py @@ -4,25 +4,20 @@ import string import sys from pathlib import Path +from typing import Optional import nest_asyncio import typer from cookiecutter.main import cookiecutter -from typing_extensions import Annotated from git import Repo -from typing import Optional +from typing_extensions import Annotated # Patch nest_asyncio before importing Chatsky nest_asyncio.apply = lambda: None from chatsky_ui.core.config import app_runner, settings # noqa: E402 from chatsky_ui.core.logger_config import get_logger # noqa: E402 -from chatsky_ui.utils.git_cmd import ( # noqa: E402 - commit_changes, - get_repo, - save_built_script_to_git, - save_frontend_graph_to_git, -) # noqa: E402 +from chatsky_ui.utils.git_cmd import commit_changes # noqa: E402 cli = typer.Typer( help="🚀 Welcome to Chatsky-UI!\n\n" @@ -108,9 +103,7 @@ def build_scenario( raise NotADirectoryError(f"Directory {project_dir} doesn't exist") settings.set_config(work_directory=project_dir) - from chatsky_ui.services.json_converter_new2.pipeline_converter import ( - PipelineConverter, - ) # pylint: disable=C0415 + from chatsky_ui.services.json_converter.pipeline_converter import PipelineConverter # pylint: disable=C0415 pipeline_converter = PipelineConverter() pipeline_converter( @@ -207,7 +200,6 @@ def init( "https://github.com/deeppavlov/chatsky-ui-template.git", no_input=no_input, overwrite_if_exists=overwrite_if_exists, - checkout="add-test", ) finally: os.chdir(original_dir) diff --git a/backend/chatsky_ui/core/config.py b/backend/chatsky_ui/core/config.py index 76321f5c..a7450f2b 100644 --- a/backend/chatsky_ui/core/config.py +++ b/backend/chatsky_ui/core/config.py @@ -1,13 +1,12 @@ +import logging import os from pathlib import Path +from typing import Dict import uvicorn from dotenv import load_dotenv -import logging -from typing import Dict from omegaconf import DictConfig, OmegaConf - LOG_LEVELS: Dict[str, int] = { "critical": logging.CRITICAL, "error": logging.ERROR, @@ -34,6 +33,7 @@ def __init__(self): self.set_config( host=os.getenv("HOST", "0.0.0.0"), port=os.getenv("PORT", "8000"), + chatsky_port=os.getenv("CHATSKY_PORT", "8020"), log_level=os.getenv("LOG_LEVEL", "info"), conf_reload=os.getenv("CONF_RELOAD", "false"), work_directory=".", @@ -45,7 +45,7 @@ def set_config(self, **kwargs): value = Path(value) elif key == "conf_reload": value = str(value).lower() in ["true", "yes", "t", "y", "1"] - elif key == "port": + elif key in ["port", "CHATSKY_PORT"]: value = int(value) setattr(self, key, value) @@ -75,6 +75,7 @@ def save_config(self): "work_directory": str(self.work_directory), "host": self.host, "port": self.port, + "chatsky_port": self.chatsky_port, "log_level": self.log_level, "conf_reload": self.conf_reload, } diff --git a/backend/chatsky_ui/core/logger_config.py b/backend/chatsky_ui/core/logger_config.py index c23ae07b..9ae891cf 100644 --- a/backend/chatsky_ui/core/logger_config.py +++ b/backend/chatsky_ui/core/logger_config.py @@ -3,7 +3,7 @@ from pathlib import Path from typing import Literal, Optional -from chatsky_ui.core.config import settings, LOG_LEVELS +from chatsky_ui.core.config import LOG_LEVELS, settings def setup_logging(log_type: Literal["builds", "runs"], id_: int, timestamp: datetime) -> Path: diff --git a/backend/chatsky_ui/main.py b/backend/chatsky_ui/main.py index 706cd5a0..5de32bd9 100644 --- a/backend/chatsky_ui/main.py +++ b/backend/chatsky_ui/main.py @@ -1,3 +1,4 @@ +import signal from contextlib import asynccontextmanager from fastapi import APIRouter, FastAPI, Response @@ -6,15 +7,27 @@ from chatsky_ui import __version__ from chatsky_ui.api.api_v1.api import api_router +from chatsky_ui.api.deps import run_manager from chatsky_ui.core.config import settings +def signal_handler(self, signum): + global stop_background_task + print("Caught termination signal, shutting down gracefully...") + for process in run_manager.processes.values(): + process.to_be_terminated = True + + @asynccontextmanager async def lifespan(app: FastAPI): if settings.temp_conf.exists(): settings.refresh_work_dir() + signal.signal(signal.SIGINT, signal_handler) yield + settings.temp_conf.unlink(missing_ok=True) + await run_manager.stop_all() + app = FastAPI(title="DF Designer", version=__version__, lifespan=lifespan) diff --git a/backend/chatsky_ui/schemas/front_graph_components/interface.py b/backend/chatsky_ui/schemas/front_graph_components/interface.py index 26ae339d..e21c1d15 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/interface.py +++ b/backend/chatsky_ui/schemas/front_graph_components/interface.py @@ -1,20 +1,18 @@ -from pydantic import Field, model_validator -from typing import Any +import os +from typing import Any, Dict, Optional -from .base_component import BaseComponent -from typing import Optional, Dict from dotenv import load_dotenv -import os +from pydantic import Field, model_validator from chatsky_ui.core.config import settings +from .base_component import BaseComponent + +load_dotenv(os.path.join(settings.work_directory, ".env"), override=True) -load_dotenv(os.path.join(settings.work_directory, ".env")) class Interface(BaseComponent): - model_config = { - "extra": "forbid" - } + model_config = {"extra": "forbid"} telegram: Optional[Dict[str, Any]] = Field(default=None) http: Optional[Dict[str, Any]] = Field(default=None) @@ -28,7 +26,6 @@ def check_one_not_none(cls, values): @model_validator(mode="after") def check_telegram_token(cls, values): - load_dotenv(os.path.join(settings.work_directory, ".env")) tg_bot_token = os.getenv("TG_BOT_TOKEN") if values.telegram is not None and not tg_bot_token: raise ValueError("Telegram token must be provided.") diff --git a/backend/chatsky_ui/schemas/front_graph_components/node.py b/backend/chatsky_ui/schemas/front_graph_components/node.py index 4911333c..1f9e56e3 100644 --- a/backend/chatsky_ui/schemas/front_graph_components/node.py +++ b/backend/chatsky_ui/schemas/front_graph_components/node.py @@ -1,4 +1,5 @@ from typing import List + from pydantic import model_validator from .base_component import BaseComponent @@ -23,7 +24,7 @@ class SlotsNode(Node): groups: List[dict] @model_validator(mode="after") - def check_unique_groups_names(cls, values) -> 'SlotsNode': + def check_unique_groups_names(cls, values) -> "SlotsNode": groups_names = [group["name"] for group in values.groups] if len(groups_names) != len(set(groups_names)): raise ValueError(f"Slot groups names should be unique. Got duplicates: {groups_names}") diff --git a/backend/chatsky_ui/services/json_converter/base_converter.py b/backend/chatsky_ui/services/json_converter/base_converter.py new file mode 100644 index 00000000..aa5dff17 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/base_converter.py @@ -0,0 +1,10 @@ +from abc import ABC, abstractmethod + + +class BaseConverter(ABC): + def __call__(self, *args, **kwargs): + return self._convert() + + @abstractmethod + def _convert(self): + raise NotImplementedError diff --git a/backend/chatsky_ui/services/json_converter/consts.py b/backend/chatsky_ui/services/json_converter/consts.py new file mode 100644 index 00000000..388bc405 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/consts.py @@ -0,0 +1,3 @@ +RESPONSES_FILE = "responses" +CONDITIONS_FILE = "conditions" +CUSTOM_FILE = "custom" diff --git a/backend/chatsky_ui/services/json_converter/flow_converter.py b/backend/chatsky_ui/services/json_converter/flow_converter.py new file mode 100644 index 00000000..ddbb1aae --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/flow_converter.py @@ -0,0 +1,72 @@ +from typing import Any, Dict, List, Tuple + +from ...schemas.front_graph_components.flow import Flow +from .base_converter import BaseConverter +from .node_converter import InfoNodeConverter, LinkNodeConverter + + +class FlowConverter(BaseConverter): + NODE_CONVERTERS = { + "default_node": InfoNodeConverter, + "link_node": LinkNodeConverter, + } + + def __init__(self, flow: Dict[str, Any]): + self._validate_flow(flow) + self.flow = Flow( + name=flow["name"], + nodes=flow["data"]["nodes"], + edges=flow["data"]["edges"], + ) + + def __call__(self, *args, **kwargs): + self.mapped_flows = kwargs["mapped_flows"] + self.slots_conf = kwargs["slots_conf"] + self._integrate_edges_into_nodes() + return super().__call__(*args, **kwargs) + + def _validate_flow(self, flow: Dict[str, Any]): + if "data" not in flow or "nodes" not in flow["data"] or "edges" not in flow["data"]: + raise ValueError("Invalid flow structure") + + def _integrate_edges_into_nodes(self): + def _insert_dst_into_condition( + node: Dict[str, Any], condition_id: str, target_node: Tuple[str, str] + ) -> Dict[str, Any]: + for condition in node["data"]["conditions"]: + if condition["id"] == condition_id: + condition["dst"] = target_node + return node + + maped_edges = self._map_edges() + nodes = self.flow.nodes.copy() + for edge in maped_edges: + for idx, node in enumerate(nodes): + if node["id"] == edge["source"]: + nodes[idx] = _insert_dst_into_condition(node, edge["sourceHandle"], edge["target"]) + self.flow.nodes = nodes + + def _map_edges(self) -> List[Dict[str, Any]]: + def _get_flow_and_node_names(target_node): + node_type = target_node["type"] + if node_type == "link_node": # TODO: WHY CONVERTING HERE? + return LinkNodeConverter(target_node)(mapped_flows=self.mapped_flows) + elif node_type == "default_node": + return [self.flow.name, target_node["data"]["name"]] + + edges = self.flow.edges.copy() + for edge in edges: + target_id = edge["target"] + target_node = self.mapped_flows[self.flow.name].get(target_id) + if target_node: + edge["target"] = _get_flow_and_node_names(target_node) + return edges + + def _convert(self) -> Dict[str, Any]: + converted_flow = {self.flow.name: {}} + for node in self.flow.nodes: + if node["type"] == "default_node": + converted_flow[self.flow.name].update( + {node["data"]["name"]: InfoNodeConverter(node)(slots_conf=self.slots_conf)} + ) + return converted_flow diff --git a/backend/chatsky_ui/services/json_converter/interface_converter.py b/backend/chatsky_ui/services/json_converter/interface_converter.py new file mode 100644 index 00000000..380a6dcc --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/interface_converter.py @@ -0,0 +1,15 @@ +from chatsky_ui.core.config import settings + +from ...schemas.front_graph_components.interface import Interface +from .base_converter import BaseConverter + + +class InterfaceConverter(BaseConverter): + def __init__(self, interface: dict): + self.interface = Interface(**interface) + + def _convert(self): + if self.interface.http is not None: + return {"chatsky.messengers.HTTPMessengerInterface": {"port": settings.chatsky_port}} + elif self.interface.telegram is not None: + return {"chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}}} diff --git a/backend/chatsky_ui/services/json_converter/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter/logic_component_converter/condition_converter.py new file mode 100644 index 00000000..a59ce3db --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/logic_component_converter/condition_converter.py @@ -0,0 +1,57 @@ +from abc import ABC, abstractmethod + +from ....core.config import settings +from ....schemas.front_graph_components.info_holders.condition import CustomCondition, SlotCondition +from ..base_converter import BaseConverter +from ..consts import CONDITIONS_FILE, CUSTOM_FILE +from .service_replacer import store_custom_service + + +class BadConditionException(Exception): + pass + + +class ConditionConverter(BaseConverter, ABC): + @abstractmethod + def get_pre_transitions(): + raise NotImplementedError + + +class CustomConditionConverter(ConditionConverter): + def __init__(self, condition: dict): + self.condition = None + try: + self.condition = CustomCondition( + name=condition["name"], + code=condition["data"]["python"]["action"], + ) + except KeyError as missing_key: + raise BadConditionException("Missing key in custom condition data") from missing_key + + def _convert(self): + store_custom_service(settings.conditions_path, [self.condition.code]) + custom_cnd = {f"{CUSTOM_FILE}.{CONDITIONS_FILE}.{self.condition.name}": None} + return custom_cnd + + def get_pre_transitions(self): + return {} + + +class SlotConditionConverter(ConditionConverter): + def __init__(self, condition: dict): + self.condition = None + try: + self.condition = SlotCondition(slot_id=condition["data"]["slot"], name=condition["name"]) + except KeyError as missing_key: + raise BadConditionException("Missing key in slot condition data") from missing_key + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return {"chatsky.conditions.slots.SlotsExtracted": self.slots_conf[self.condition.slot_id]} + + def get_pre_transitions(self): + slot_path = self.slots_conf[self.condition.slot_id] # type: ignore + return {slot_path: {"chatsky.processing.slots.Extract": slot_path}} diff --git a/backend/chatsky_ui/services/json_converter/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter/logic_component_converter/response_converter.py new file mode 100644 index 00000000..cb2624ee --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/logic_component_converter/response_converter.py @@ -0,0 +1,42 @@ +from ....core.config import settings +from ....schemas.front_graph_components.info_holders.response import CustomResponse, TextResponse +from ..base_converter import BaseConverter +from ..consts import CUSTOM_FILE, RESPONSES_FILE +from .service_replacer import store_custom_service + + +class BadResponseException(Exception): + pass + + +class ResponseConverter(BaseConverter): + pass + + +class TextResponseConverter(ResponseConverter): + def __init__(self, response: dict): + try: + self.response = TextResponse( + name=response["name"], + text=next(iter(response["data"]))["text"], + ) + except KeyError as e: + raise BadResponseException("Missing key in custom condition data") from e + + def _convert(self): + return {"chatsky.Message": {"text": self.response.text}} + + +class CustomResponseConverter(ResponseConverter): + def __init__(self, response: dict): + try: + self.response = CustomResponse( + name=response["name"], + code=next(iter(response["data"]))["python"]["action"], + ) + except KeyError as e: + raise BadResponseException("Missing key in custom response data") from e + + def _convert(self): + store_custom_service(settings.responses_path, [self.response.code]) + return {f"{CUSTOM_FILE}.{RESPONSES_FILE}.{self.response.name}": None} diff --git a/backend/chatsky_ui/services/json_converter/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter/logic_component_converter/service_replacer.py new file mode 100644 index 00000000..6dee45c1 --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/logic_component_converter/service_replacer.py @@ -0,0 +1,82 @@ +import ast +from ast import NodeTransformer +from pathlib import Path +from typing import Dict, List + +from chatsky_ui.core.logger_config import get_logger + + +class ServiceReplacer(NodeTransformer): + def __init__(self, new_services: List[str]): + self.new_services_classes = self._get_classes_def(new_services) + self._logger = None + + @property + def logger(self): + if self._logger is None: + raise ValueError("Logger has not been configured. Call set_logger() first.") + return self._logger + + def set_logger(self): + self._logger = get_logger(__name__) + + def _get_classes_def(self, services_code: List[str]) -> Dict[str, ast.ClassDef]: + parsed_codes = [ast.parse(service_code) for service_code in services_code] + for idx, parsed_code in enumerate(parsed_codes): + classes = self._extract_class_defs(parsed_code, services_code[idx]) + return classes + + def _extract_class_defs(self, parsed_code: ast.Module, service_code: str): + classes = {} + for node in parsed_code.body: + if isinstance(node, ast.ClassDef): + classes[node.name] = node + else: + self.logger.error("No class definition found in new_service: %s", service_code) + return classes + + def visit_ClassDef(self, node: ast.ClassDef) -> ast.ClassDef: + self.logger.debug("Visiting class '%s' and comparing with: %s", node.name, self.new_services_classes.keys()) + if node.name in self.new_services_classes: + return self._get_class_def(node) + return node + + def _get_class_def(self, node: ast.ClassDef) -> ast.ClassDef: + service = self.new_services_classes[node.name] + del self.new_services_classes[node.name] + self.logger.info("Updating class '%s'", node.name) + return service + + def generic_visit(self, node: ast.AST): + super().generic_visit(node) + if isinstance(node, ast.Module) and self.new_services_classes: + self._append_new_services(node) + return node + + def _append_new_services(self, node: ast.Module): + self.logger.info("Services not found, appending new services: %s", list(self.new_services_classes.keys())) + for _, service in self.new_services_classes.items(): + node.body.append(service) + + +def store_custom_service(services_path: Path, services: List[str]): + with open(services_path, "r", encoding="UTF-8") as file: + conditions_tree = ast.parse(file.read()) + + replacer = ServiceReplacer(services) + replacer.set_logger() + replacer.visit(conditions_tree) + + with open(services_path, "w") as file: + file.write(ast.unparse(conditions_tree)) + + +def get_all_classes(services_path): + with open(services_path, "r", encoding="UTF-8") as file: + conditions_tree = ast.parse(file.read()) + + return [ + {"name": node.name, "body": ast.unparse(node)} + for node in conditions_tree.body + if isinstance(node, ast.ClassDef) + ] diff --git a/backend/chatsky_ui/services/json_converter/node_converter.py b/backend/chatsky_ui/services/json_converter/node_converter.py new file mode 100644 index 00000000..9656479b --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/node_converter.py @@ -0,0 +1,84 @@ +from chatsky import PRE_RESPONSE, PRE_TRANSITION, RESPONSE, TRANSITIONS + +from ...schemas.front_graph_components.node import InfoNode, LinkNode +from .base_converter import BaseConverter +from .logic_component_converter.condition_converter import CustomConditionConverter, SlotConditionConverter +from .logic_component_converter.response_converter import CustomResponseConverter, TextResponseConverter + + +class NodeConverter(BaseConverter): + RESPONSE_CONVERTER = { + "text": TextResponseConverter, + "python": CustomResponseConverter, + } + CONDITION_CONVERTER = { + "python": CustomConditionConverter, + "slot": SlotConditionConverter, + } + + def __init__(self, config: dict): + pass + + +class InfoNodeConverter(NodeConverter): + MAP_TR2CHATSKY = { + "start": "dst.Start", + "fallback": "dst.Fallback", + "previous": "dst.Previous", + "repeat": "dst.Current", + } + + def __init__(self, node: dict): + self.node = InfoNode( + id=node["id"], + name=node["data"]["name"], + response=node["data"]["response"], + conditions=node["data"]["conditions"], + ) + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + condition_converters = [ + self.CONDITION_CONVERTER[condition["type"]](condition) for condition in self.node.conditions + ] + return { + RESPONSE: self.RESPONSE_CONVERTER[self.node.response["type"]](self.node.response)(), + TRANSITIONS: [ + { + "dst": condition["dst"] + if "dst" in condition and condition["data"]["transition_type"] == "manual" + else self.MAP_TR2CHATSKY[condition["data"]["transition_type"]], + "priority": condition["data"]["priority"], + "cnd": converter(slots_conf=self.slots_conf), + } + for condition, converter in zip(self.node.conditions, condition_converters) + ], + PRE_TRANSITION: { + key: value + for converter in condition_converters + for key, value in converter.get_pre_transitions().items() + }, + PRE_RESPONSE: {"fill": {"chatsky.processing.FillTemplate": None}}, + } + + +class LinkNodeConverter(NodeConverter): + def __init__(self, config: dict): + self.node = LinkNode( + id=config["id"], + target_flow_name=config["data"]["transition"]["target_flow"], + target_node_id=config["data"]["transition"]["target_node"], + ) + + def __call__(self, *args, **kwargs): + self.mapped_flows = kwargs["mapped_flows"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return [ + self.node.target_flow_name, + self.mapped_flows[self.node.target_flow_name][self.node.target_node_id]["data"]["name"], + ] diff --git a/backend/chatsky_ui/services/json_converter/pipeline_converter.py b/backend/chatsky_ui/services/json_converter/pipeline_converter.py new file mode 100644 index 00000000..969640fe --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/pipeline_converter.py @@ -0,0 +1,48 @@ +from pathlib import Path + +import yaml + +try: + from yaml import CDumper as Dumper + from yaml import CLoader as Loader +except ImportError: + from yaml import Loader, Dumper + +from ...schemas.front_graph_components.pipeline import Pipeline +from .base_converter import BaseConverter +from .interface_converter import InterfaceConverter +from .script_converter import ScriptConverter +from .slots_converter import SlotsConverter + + +class PipelineConverter(BaseConverter): + def __call__(self, input_file: Path, output_dir: Path): + self.from_yaml(file_path=input_file) + + self.pipeline = Pipeline(**self.graph) + self.converted_pipeline = super().__call__() + + self.to_yaml(dir_path=output_dir) + + def from_yaml(self, file_path: Path): + with open(str(file_path), "r", encoding="UTF-8") as file: + self.graph = yaml.load(file, Loader=Loader) + + def to_yaml(self, dir_path: Path): + with open(f"{dir_path}/build.yaml", "w", encoding="UTF-8") as file: + yaml.dump(self.converted_pipeline, file, Dumper=Dumper, default_flow_style=False) + + def _convert(self): + slots_converter = SlotsConverter(self.pipeline.flows) + script_converter = ScriptConverter(self.pipeline.flows) + + slots_conf = slots_converter.map_slots() + start_label, fallback_label = script_converter.extract_start_fallback_labels() + + return { + "script": script_converter(slots_conf=slots_conf), + "messenger_interface": InterfaceConverter(self.pipeline.interface)(), + "slots": slots_converter(), + "start_label": start_label, + "fallback_label": fallback_label, + } diff --git a/backend/chatsky_ui/services/json_converter/script_converter.py b/backend/chatsky_ui/services/json_converter/script_converter.py new file mode 100644 index 00000000..f1f2197d --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/script_converter.py @@ -0,0 +1,51 @@ +from typing import List + +from ...schemas.front_graph_components.script import Script +from .base_converter import BaseConverter +from .flow_converter import FlowConverter + + +class ScriptConverter(BaseConverter): + def __init__(self, flows: List[dict]): + self.script = Script(flows=flows) + self.mapped_flows = self._map_flows() # TODO: think about storing this in a temp file + + def __call__(self, *args, **kwargs): + self.slots_conf = kwargs["slots_conf"] + return super().__call__(*args, **kwargs) + + def _convert(self): + return { + key: value + for flow in self.script.flows + for key, value in FlowConverter(flow)(mapped_flows=self.mapped_flows, slots_conf=self.slots_conf).items() + } + + def _map_flows(self): + mapped_flows = {} + for flow in self.script.flows: + mapped_flows[flow["name"]] = {} + for node in flow["data"]["nodes"]: + mapped_flows[flow["name"]][node["id"]] = node + return mapped_flows + + def extract_start_fallback_labels(self): # TODO: refactor this huge method + start_label, fallback_label = None, None + + for flow in self.script.flows: + for node in flow["data"]["nodes"]: + flags = node["data"].get("flags", []) + + if "start" in flags: + if start_label: + raise ValueError("Multiple start nodes found") + start_label = [flow["name"], node["data"]["name"]] + if "fallback" in flags: + if fallback_label: + raise ValueError("Multiple fallback nodes found") + fallback_label = [flow["name"], node["data"]["name"]] + + if start_label and fallback_label: + return start_label, fallback_label + + return start_label, fallback_label # return None, None diff --git a/backend/chatsky_ui/services/json_converter/slots_converter.py b/backend/chatsky_ui/services/json_converter/slots_converter.py new file mode 100644 index 00000000..3bd9970b --- /dev/null +++ b/backend/chatsky_ui/services/json_converter/slots_converter.py @@ -0,0 +1,75 @@ +from typing import List + +from ...schemas.front_graph_components.node import SlotsNode +from ...schemas.front_graph_components.slot import GroupSlot, RegexpSlot +from .base_converter import BaseConverter + + +class SlotsConverter(BaseConverter): + def __init__(self, flows: List[dict]): + def _get_slots_node(flows): + return next( + iter([node for flow in flows for node in flow["data"]["nodes"] if node["type"] == "slots_node"]), + {"id": "999999", "data": {"groups": []}}, + ) + + slots_node = _get_slots_node(flows) + self.slots_node = SlotsNode( + id=slots_node["id"], + groups=slots_node["data"]["groups"], + ) + + def map_slots(self): + mapped_slots = {} + for group in self.slots_node.groups.copy(): + for slot in group["slots"]: + mapped_slots[slot["id"]] = ".".join([group["name"], slot["name"]]) + return mapped_slots + + def _convert(self): + return {key: value for group in self.slots_node.groups for key, value in GroupSlotConverter(group)().items()} + + +class RegexpSlotConverter(SlotsConverter): + def __init__(self, slot: dict): + self.slot = RegexpSlot( + id=slot["id"], + name=slot["name"], + regexp=slot["value"], + match_group_idx=slot.get("match_group_idx", 1), + ) + + def _convert(self): + return { + self.slot.name: { + "chatsky.slots.RegexpSlot": { + "regexp": self.slot.regexp, + "match_group_idx": self.slot.match_group_idx, + } + } + } + + +class GroupSlotConverter(SlotsConverter): + SLOTS_CONVERTER_TYPES = { + "GroupSlot": "self", # Placeholder, will be replaced in __init__ + "RegexpSlot": RegexpSlotConverter, + } + + def __init__(self, slot: dict): + # Replace the placeholder with the actual class reference + self.SLOTS_CONVERTER_TYPES["GroupSlot"] = GroupSlotConverter + + self.slot = GroupSlot( + name=slot["name"], + slots=slot["slots"], + ) + + def _convert(self): + return { + self.slot.name: { + key: value + for slot in self.slot.slots + for key, value in self.SLOTS_CONVERTER_TYPES[slot["type"]](slot)().items() + } + } diff --git a/backend/chatsky_ui/services/process.py b/backend/chatsky_ui/services/process.py index c3b4a821..7ae7020d 100644 --- a/backend/chatsky_ui/services/process.py +++ b/backend/chatsky_ui/services/process.py @@ -12,17 +12,15 @@ from datetime import datetime from pathlib import Path from typing import Any, Dict, List, Optional -from httpx import AsyncClient -from chatsky.messengers.http_interface import HTTP_INTERFACE_PORT from dotenv import load_dotenv +from httpx import AsyncClient from chatsky_ui.core.config import settings from chatsky_ui.core.logger_config import get_logger, setup_logging from chatsky_ui.db.base import read_conf, write_conf from chatsky_ui.schemas.process_status import Status -from chatsky_ui.utils.git_cmd import get_repo, save_frontend_graph_to_git, save_built_script_to_git - +from chatsky_ui.utils.git_cmd import get_repo, save_built_script_to_git load_dotenv() @@ -42,6 +40,7 @@ def __init__(self, id_: int, preset_end_status: str = ""): self.lock: asyncio.Lock = asyncio.Lock() self.process: Optional[asyncio.subprocess.Process] = None self.logger: logging.Logger + self.to_be_terminated = False async def start(self, cmd_to_run: str) -> None: """Starts an asyncronous process with the given command.""" @@ -63,6 +62,7 @@ async def get_full_info(self, attributes: list) -> Dict[str, Any]: Returns: dict: A dictionary containing the values of the attributes mentioned in the list. """ + def _map_to_str(params: Dict[str, Any]): for k, v in params.copy().items(): if isinstance(v, datetime): @@ -84,10 +84,16 @@ async def update_db_info(self): async def periodically_check_status(self) -> None: """Periodically checks the process status and updates the database.""" - while True: + while not self.to_be_terminated: await self.update_db_info() # check status and update db self.logger.info("Status of process '%s': %s", self.id, self.status) - if self.status in [Status.NULL, Status.STOPPED, Status.COMPLETED, Status.FAILED]: + if self.status in [ + Status.NULL, + Status.STOPPED, + Status.COMPLETED, + Status.FAILED, + Status.FAILED_WITH_UNEXPECTED_CODE, + ]: break await asyncio.sleep(2) # TODO: ?sleep time shouldn't be constant @@ -163,7 +169,7 @@ async def stop(self) -> None: self.logger.error("Process group '%s' not found. It may have already exited.", self.id) raise ProcessLookupError from exc - def add_new_conf(self, conf: list, params: dict) -> list: #TODO: rename conf everywhere to metadata/meta + def add_new_conf(self, conf: list, params: dict) -> list: # TODO: rename conf everywhere to metadata/meta for run in conf: if run.id == params["id"]: # type: ignore for key, value in params.items(): @@ -196,7 +202,7 @@ async def update_db_info(self) -> None: runs_conf = await read_conf(settings.runs_path) run_params = await self.get_full_info() - runs_conf = self.add_new_conf(runs_conf, run_params) # type: ignore + runs_conf = self.add_new_conf(runs_conf, run_params) # type: ignore await write_conf(runs_conf, settings.runs_path) @@ -209,9 +215,10 @@ async def update_db_info(self) -> None: break await write_conf(builds_conf, settings.builds_path) - + async def is_alive(self) -> bool: """Checks if the process is alive by writing to stdin andreading its stdout.""" + async def check_telegram_readiness(stream, name): async for line in stream: decoded_line = line.decode().strip() @@ -225,12 +232,12 @@ async def check_telegram_readiness(stream, name): async with AsyncClient() as client: try: response = await client.get( - f"http://localhost:{HTTP_INTERFACE_PORT}/health", + f"http://localhost:{settings.chatsky_port}/health", ) return response.json()["status"] == "ok" except Exception as e: self.logger.info( - f"Process '{self.id}' isn't alive on port '{HTTP_INTERFACE_PORT}' yet. " + f"Process '{self.id}' isn't alive on port '{settings.chatsky_port}' yet. " f"Ignore this if you're not connecting via HTTPInterface. Exception caught: {e}" ) @@ -274,7 +281,7 @@ async def update_db_info(self) -> None: builds_conf = await read_conf(settings.builds_path) build_params = await self.get_full_info() - builds_conf = self.add_new_conf(builds_conf, build_params) # type: ignore + builds_conf = self.add_new_conf(builds_conf, build_params) # type: ignore await write_conf(builds_conf, settings.builds_path) @@ -284,7 +291,7 @@ def save_built_script_to_git(self, id_: int) -> None: async def periodically_check_status(self) -> None: """Periodically checks the process status and updates the database.""" - while True: + while not self.to_be_terminated: await self.update_db_info() # check status and update db self.logger.info("Status of process '%s': %s", self.id, self.status) if self.status in [Status.NULL, Status.STOPPED, Status.COMPLETED, Status.FAILED]: @@ -293,4 +300,4 @@ async def periodically_check_status(self) -> None: await asyncio.sleep(2) # TODO: ?sleep time shouldn't be constant async def is_alive(self) -> bool: - return False + return False \ No newline at end of file diff --git a/backend/chatsky_ui/services/process_manager.py b/backend/chatsky_ui/services/process_manager.py index 8184fc7d..6f8744e2 100644 --- a/backend/chatsky_ui/services/process_manager.py +++ b/backend/chatsky_ui/services/process_manager.py @@ -6,9 +6,11 @@ starting, stopping, updating, and checking status of processes. Processes themselves are stored in the `processes` dictionary of process managers. """ +import os from pathlib import Path from typing import Any, Dict, List, Optional, Union +from dotenv import load_dotenv from omegaconf import OmegaConf from chatsky_ui.core.config import settings @@ -57,10 +59,10 @@ async def stop(self, id_: int) -> None: raise async def stop_all(self) -> None: - self.logger.info("Stopping all process %s", self.processes) for id_, process in self.processes.items(): - if process.process.returncode is None: + if await process.check_status() in [Status.ALIVE, Status.RUNNING]: await self.stop(id_) + await process.update_db_info() async def check_status(self, id_: int, *args, **kwargs) -> None: """Checks the status of the process with the given id by calling the `periodically_check_status` @@ -135,6 +137,8 @@ async def start(self, build_id: int, preset: Preset) -> int: self.last_id += 1 id_ = self.last_id process = RunProcess(id_, build_id, preset.end_status) + + load_dotenv(os.path.join(settings.work_directory, ".env"), override=True) await process.start(cmd_to_run) process.logger.debug("Started process. status: '%s'", process.process.returncode) self.processes[id_] = process @@ -178,18 +182,16 @@ async def start(self, preset: Preset) -> int: id_ = self.last_id if self.is_repeated_id(id_): - raise ValueError(f"Build id '{id_}' already exists in the database") + raise ValueError(f"Build id '{id_}' already exists in the database") process = BuildProcess(id_, preset.end_status) if self.is_changed_graph(id_): cmd_to_run = ( - f"chatsky.ui build_bot " - f"--preset {preset.end_status} " - f"--project-dir {settings.work_directory}" + f"chatsky.ui build_bot " f"--preset {preset.end_status} " f"--project-dir {settings.work_directory}" ) await process.start(cmd_to_run) self.processes[id_] = process - + return self.last_id async def check_status(self, id_, *args, **kwargs): diff --git a/backend/chatsky_ui/tests/api/test_bot.py b/backend/chatsky_ui/tests/api/test_bot.py index f6b5c2b4..20f70b5e 100644 --- a/backend/chatsky_ui/tests/api/test_bot.py +++ b/backend/chatsky_ui/tests/api/test_bot.py @@ -6,7 +6,6 @@ _stop_process, check_build_processes, check_run_processes, - connect, get_build_logs, get_run_logs, start_build, @@ -16,8 +15,6 @@ from chatsky_ui.services.process_manager import RunManager PROCESS_ID = 0 -RUN_ID = 0 -BUILD_ID = 0 @pytest.mark.asyncio @@ -63,27 +60,27 @@ async def test_check_process_status(mocker): @pytest.mark.asyncio -async def test_start_build(mocker): +async def test_start_build(mocker, dummy_build_id): build_manager = mocker.MagicMock() preset = mocker.MagicMock() - start = mocker.AsyncMock(return_value=BUILD_ID) + start = mocker.AsyncMock(return_value=dummy_build_id) mocker.patch.multiple(build_manager, start=start, check_status=mocker.AsyncMock()) mocker.patch.multiple(preset, wait_time=0, end_status="loop") response = await start_build(preset, background_tasks=BackgroundTasks(), build_manager=build_manager) start.assert_awaited_once_with(preset) - assert response == {"status": "ok", "build_id": BUILD_ID} + assert response == {"status": "ok", "build_id": dummy_build_id} @pytest.mark.asyncio -async def test_check_build_processes_some_info(mocker, pagination): +async def test_check_build_processes_some_info(mocker, pagination, dummy_build_id): build_manager = mocker.AsyncMock() run_manager = mocker.AsyncMock() - await check_build_processes(BUILD_ID, build_manager, run_manager, pagination) + await check_build_processes(dummy_build_id, build_manager, run_manager, pagination) - build_manager.get_build_info.assert_awaited_once_with(BUILD_ID, run_manager) + build_manager.get_build_info.assert_awaited_once_with(dummy_build_id, run_manager) @pytest.mark.asyncio @@ -100,37 +97,37 @@ async def test_check_build_processes_all_info(mocker, pagination): @pytest.mark.asyncio -async def test_get_build_logs(mocker, pagination): +async def test_get_build_logs(mocker, pagination, dummy_build_id): build_manager = mocker.AsyncMock() - await get_build_logs(BUILD_ID, build_manager, pagination) + await get_build_logs(dummy_build_id, build_manager, pagination) - build_manager.fetch_build_logs.assert_awaited_once_with(BUILD_ID, pagination.offset(), pagination.limit) + build_manager.fetch_build_logs.assert_awaited_once_with(dummy_build_id, pagination.offset(), pagination.limit) @pytest.mark.asyncio -async def test_start_run(mocker): +async def test_start_run(mocker, dummy_build_id, dummy_run_id): run_manager = mocker.MagicMock() preset = mocker.MagicMock() - start = mocker.AsyncMock(return_value=RUN_ID) + start = mocker.AsyncMock(return_value=dummy_run_id) mocker.patch.multiple(run_manager, start=start, check_status=mocker.AsyncMock()) mocker.patch.multiple(preset, wait_time=0, end_status="loop") response = await start_run( - build_id=BUILD_ID, preset=preset, background_tasks=BackgroundTasks(), run_manager=run_manager + build_id=dummy_build_id, preset=preset, background_tasks=BackgroundTasks(), run_manager=run_manager ) - start.assert_awaited_once_with(BUILD_ID, preset) - assert response == {"status": "ok", "run_id": RUN_ID} + start.assert_awaited_once_with(dummy_build_id, preset) + assert response == {"status": "ok", "run_id": dummy_run_id} @pytest.mark.asyncio -async def test_check_run_processes_some_info(mocker, pagination): +async def test_check_run_processes_some_info(mocker, pagination, dummy_run_id): run_manager = mocker.AsyncMock() - await check_run_processes(RUN_ID, run_manager, pagination) + await check_run_processes(dummy_run_id, run_manager, pagination) - run_manager.get_run_info.assert_awaited_once_with(RUN_ID) + run_manager.get_run_info.assert_awaited_once_with(dummy_run_id) @pytest.mark.asyncio @@ -144,27 +141,9 @@ async def test_check_run_processes_all_info(mocker, pagination): @pytest.mark.asyncio -async def test_get_run_logs(mocker, pagination): +async def test_get_run_logs(mocker, pagination, dummy_run_id): run_manager = mocker.AsyncMock() - await get_run_logs(RUN_ID, run_manager, pagination) + await get_run_logs(dummy_run_id, run_manager, pagination) - run_manager.fetch_run_logs.assert_awaited_once_with(RUN_ID, pagination.offset(), pagination.limit) - - -@pytest.mark.asyncio -async def test_connect(mocker): - websocket = mocker.AsyncMock() - websocket_manager = mocker.AsyncMock() - websocket_manager.disconnect = mocker.MagicMock() - run_manager = mocker.AsyncMock() - run_process = mocker.AsyncMock() - run_manager.processes = {RUN_ID: run_process} - mocker.patch.object(websocket, "query_params", {"run_id": str(RUN_ID)}) - - await connect(websocket, websocket_manager, run_manager) - - websocket_manager.connect.assert_awaited_once_with(websocket) - websocket_manager.send_process_output_to_websocket.assert_awaited_once_with(RUN_ID, run_manager, websocket) - websocket_manager.forward_websocket_messages_to_process.assert_awaited_once_with(RUN_ID, run_manager, websocket) - websocket_manager.disconnect.assert_called_once_with(websocket) + run_manager.fetch_run_logs.assert_awaited_once_with(dummy_run_id, pagination.offset(), pagination.limit) diff --git a/backend/chatsky_ui/tests/conftest.py b/backend/chatsky_ui/tests/conftest.py index 2f4d1987..18046da9 100644 --- a/backend/chatsky_ui/tests/conftest.py +++ b/backend/chatsky_ui/tests/conftest.py @@ -15,11 +15,18 @@ from chatsky_ui.main import app from chatsky_ui.schemas.pagination import Pagination from chatsky_ui.schemas.preset import Preset -from chatsky_ui.services.process import RunProcess +from chatsky_ui.services.process import BuildProcess, RunProcess from chatsky_ui.services.process_manager import BuildManager, RunManager -DUMMY_BUILD_ID = -1 +@pytest.fixture(scope="session") +def dummy_build_id() -> int: + return 999999 + + +@pytest.fixture(scope="session") +def dummy_run_id() -> int: + return 999999 async def start_process(async_client: AsyncClient, endpoint, preset_end_status) -> httpx.Response: @@ -29,18 +36,22 @@ async def start_process(async_client: AsyncClient, endpoint, preset_end_status) ) -@asynccontextmanager -async def override_dependency(mocker_obj, get_manager_func): - process_manager = get_manager_func() - process_manager.check_status = mocker_obj.AsyncMock() - app.dependency_overrides[get_manager_func] = lambda: process_manager - try: - yield process_manager - finally: - for _, process in process_manager.processes.items(): - if process.process.returncode is None: - await process.stop() - app.dependency_overrides = {} +@pytest.fixture +def override_dependency(mocker): + @asynccontextmanager + async def _override_dependency(get_manager_func): + process_manager = get_manager_func() + process_manager.check_status = mocker.AsyncMock() + app.dependency_overrides[get_manager_func] = lambda: process_manager + try: + yield process_manager + finally: + for _, process in process_manager.processes.items(): + if process.process.returncode is None: + await process.stop() + app.dependency_overrides = {} + + return _override_dependency @pytest.fixture @@ -63,15 +74,25 @@ def pagination() -> Pagination: @pytest.fixture() -def run_process(): - async def _run_process(cmd_to_run): - process = RunProcess(id_=0, build_id=DUMMY_BUILD_ID) +def run_process(dummy_build_id, dummy_run_id): + async def _run_process(cmd_to_run) -> RunProcess: + process = RunProcess(id_=dummy_run_id, build_id=dummy_build_id) await process.start(cmd_to_run) return process return _run_process +@pytest.fixture() +def build_process(dummy_build_id): + async def _build_process(cmd_to_run) -> BuildProcess: + process = BuildProcess(id_=dummy_build_id) + await process.start(cmd_to_run) + return process + + return _build_process + + @pytest.fixture() def run_manager(): manager = RunManager() @@ -82,4 +103,3 @@ def run_manager(): @pytest.fixture() def build_manager(): return BuildManager() - diff --git a/backend/chatsky_ui/tests/integration/test_bot.py b/backend/chatsky_ui/tests/integration/test_bot.py new file mode 100644 index 00000000..4908c8f5 --- /dev/null +++ b/backend/chatsky_ui/tests/integration/test_bot.py @@ -0,0 +1,97 @@ +import asyncio +import os + +import pytest +from dotenv import load_dotenv +from httpx import AsyncClient +from httpx._transports.asgi import ASGITransport + +from chatsky_ui.api.deps import get_build_manager, get_run_manager +from chatsky_ui.core.logger_config import get_logger +from chatsky_ui.main import app +from chatsky_ui.schemas.process_status import Status + +load_dotenv() + +BUILD_COMPLETION_TIMEOUT = float(os.getenv("BUILD_COMPLETION_TIMEOUT", 10)) +RUN_RUNNING_TIMEOUT = float(os.getenv("RUN_RUNNING_TIMEOUT", 5)) + +logger = get_logger(__name__) + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "preset_status, expected_status", + [("failure", Status.FAILED), ("loop", Status.RUNNING), ("success", Status.COMPLETED)], +) +async def test_start_build(mocker, override_dependency, preset_status, expected_status): + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as async_client: + async with override_dependency(get_build_manager) as process_manager: + process_manager.save_built_script_to_git = mocker.MagicMock() + process_manager.is_changed_graph = mocker.MagicMock(return_value=True) + + response = await async_client.post( + "/api/v1/bot/build/start", + json={"wait_time": 0.1, "end_status": preset_status}, + ) + + assert response.json().get("status") == "ok", "Start process response status is not 'ok'" + + process_id = process_manager.last_id + process = process_manager.processes[process_id] + + try: + await asyncio.wait_for(process.process.wait(), timeout=BUILD_COMPLETION_TIMEOUT) + except asyncio.exceptions.TimeoutError as exc: + if preset_status == "loop": + logger.debug("Loop process timed out. Expected behavior.") + assert True + await process.stop() + return + else: + raise Exception( + f"Process with expected end status '{preset_status}' timed out with " + f"return code '{process.process.returncode}'." + ) from exc + + current_status = await process_manager.get_status(process_id) + assert ( + current_status == expected_status + ), f"Current process status '{current_status}' did not match the expected '{expected_status}'" + + +@pytest.mark.asyncio +@pytest.mark.parametrize( + "preset_status, expected_status", [("failure", Status.FAILED), ("loop", Status.RUNNING), ("success", Status.ALIVE)] +) +async def test_start_run(override_dependency, preset_status, expected_status, dummy_build_id): + async with AsyncClient(transport=ASGITransport(app=app), base_url="http://test") as async_client: + async with override_dependency(get_run_manager) as process_manager: + response = await async_client.post( + f"/api/v1/bot/run/start/{dummy_build_id}", + json={"wait_time": 0.1, "end_status": preset_status}, + ) + + assert response.json().get("status") == "ok", "Start process response status is not 'ok'" + + process_id = process_manager.last_id + process = process_manager.processes[process_id] + + try: + await asyncio.wait_for(process.process.wait(), timeout=RUN_RUNNING_TIMEOUT) + except asyncio.exceptions.TimeoutError as exc: + if preset_status == "loop": + logger.debug("Loop process timed out. Expected behavior.") + assert True + await process.stop() + return + else: + raise Exception( + f"Process with expected end status '{preset_status}' timed out with " + f"return code '{process.process.returncode}'." + ) from exc + + current_status = await process_manager.get_status(process_id) + assert ( + current_status == expected_status + ), f"Current process status '{current_status}' did not match the expected '{expected_status}'" diff --git a/backend/chatsky_ui/tests/services/test_process.py b/backend/chatsky_ui/tests/services/test_process.py index c0c958db..2fb1af42 100644 --- a/backend/chatsky_ui/tests/services/test_process.py +++ b/backend/chatsky_ui/tests/services/test_process.py @@ -2,10 +2,19 @@ import pytest +from chatsky_ui.core.config import settings +from chatsky_ui.db.base import read_conf from chatsky_ui.schemas.process_status import Status class TestRunProcess: + @pytest.mark.asyncio + async def test_get_full_info(self, run_process): + process = await run_process("sleep 10000") + await asyncio.sleep(2) + info = await process.get_full_info(["status", "timestamp"]) + assert info["status"] == Status.RUNNING.value + @pytest.mark.asyncio @pytest.mark.parametrize( "cmd_to_run, status", @@ -20,10 +29,6 @@ async def test_check_status(self, run_process, cmd_to_run, status): await asyncio.sleep(2) assert await process.check_status() == status - # def test_periodically_check_status(self, run_process): - # process = await run_process("sleep 10000") - # run_process.periodically_check_status() - @pytest.mark.asyncio async def test_stop(self, run_process): process = await run_process("sleep 10000") @@ -31,18 +36,19 @@ async def test_stop(self, run_process): assert process.process.returncode == -15 @pytest.mark.asyncio - async def test_read_stdout(self, run_process): + async def test_update_db_info(self, run_process, dummy_run_id): process = await run_process("echo Hello") - output = await process.read_stdout() - assert output.strip().decode() == "Hello" + await process.update_db_info() - @pytest.mark.asyncio - async def test_write_stdout(self, run_process): - process = await run_process("cat") - await process.write_stdin(b"Chatsky-UI team welcome you.\n") - output = await process.process.stdout.readline() - assert output.decode().strip() == "Chatsky-UI team welcome you." + runs_conf = await read_conf(settings.runs_path) + assert dummy_run_id in [conf["id"] for conf in runs_conf] # type: ignore -# class TestBuildProcess: -# pass +class TestBuildProcess: + @pytest.mark.asyncio + async def test_update_db_info(self, build_process, dummy_build_id): + process = await build_process("echo Hello") + await process.update_db_info() + + builds_conf = await read_conf(settings.builds_path) + assert dummy_build_id in [conf["id"] for conf in builds_conf] # type: ignore diff --git a/backend/chatsky_ui/tests/services/test_websocket_manager.py b/backend/chatsky_ui/tests/services/test_websocket_manager.py deleted file mode 100644 index ada2589a..00000000 --- a/backend/chatsky_ui/tests/services/test_websocket_manager.py +++ /dev/null @@ -1,57 +0,0 @@ -import pytest -from fastapi import WebSocket - - -class TestWebSocketManager: - @pytest.mark.asyncio - async def test_connect(self, mocker, websocket_manager): - mocked_websocket = mocker.MagicMock(spec=WebSocket) - - await websocket_manager.connect(mocked_websocket) - - mocked_websocket.accept.assert_awaited_once_with() - assert mocked_websocket in websocket_manager.active_connections - - @pytest.mark.asyncio - async def test_disconnect(self, mocker, websocket_manager): - mocked_websocket = mocker.MagicMock(spec=WebSocket) - websocket_manager.active_connections.append(mocked_websocket) - websocket_manager.pending_tasks[mocked_websocket] = set() - - websocket_manager.disconnect(mocked_websocket) - - assert mocked_websocket not in websocket_manager.pending_tasks - assert mocked_websocket not in websocket_manager.active_connections - - @pytest.mark.asyncio - async def test_send_process_output_to_websocket(self, mocker, websocket_manager): - run_id = 42 - awaited_response = "Hello from DF-Designer" - - websocket = mocker.AsyncMock() - run_manager = mocker.MagicMock() - run_process = mocker.MagicMock() - run_process.read_stdout = mocker.AsyncMock(side_effect=[awaited_response.encode(), None]) - run_manager.processes = {run_id: run_process} - - await websocket_manager.send_process_output_to_websocket(run_id, run_manager, websocket) - - assert run_process.read_stdout.call_count == 2 - websocket.send_text.assert_awaited_once_with(awaited_response) - - @pytest.mark.asyncio - async def test_forward_websocket_messages_to_process(self, mocker, websocket_manager): - run_id = 42 - awaited_message = "Hello from DF-Designer" - - websocket = mocker.AsyncMock() - websocket.receive_text = mocker.AsyncMock(side_effect=[awaited_message, None]) - run_manager = mocker.MagicMock() - run_process = mocker.MagicMock() - run_process.write_stdin = mocker.AsyncMock() - run_manager.processes = {run_id: run_process} - - await websocket_manager.forward_websocket_messages_to_process(run_id, run_manager, websocket) - - assert websocket.receive_text.await_count == 2 - run_process.write_stdin.assert_called_once_with(awaited_message.encode() + b"\n") diff --git a/backend/chatsky_ui/tests/unit/conftest.py b/backend/chatsky_ui/tests/unit/conftest.py index 1ccea99b..28008cfd 100644 --- a/backend/chatsky_ui/tests/unit/conftest.py +++ b/backend/chatsky_ui/tests/unit/conftest.py @@ -1,6 +1,6 @@ import pytest +from chatsky import PRE_RESPONSE, PRE_TRANSITION, RESPONSE, TRANSITIONS -from chatsky import PRE_RESPONSE, RESPONSE, TRANSITIONS, PRE_TRANSITION @pytest.fixture def custom_condition(): @@ -138,13 +138,9 @@ def mapped_flow(info_node): @pytest.fixture def telegram_interface(): - return { - "telegram": {} - } + return {"telegram": {}} @pytest.fixture def chatsky_telegram_interface(): - return { - "chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} - } + return {"chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}}} diff --git a/backend/chatsky_ui/tests/unit/test_flow_converter.py b/backend/chatsky_ui/tests/unit/test_flow_converter.py index cb53310b..2d87d325 100644 --- a/backend/chatsky_ui/tests/unit/test_flow_converter.py +++ b/backend/chatsky_ui/tests/unit/test_flow_converter.py @@ -1,21 +1,18 @@ -import pytest -from pathlib import Path import os +from pathlib import Path + +import pytest import yaml -from chatsky_ui.services.json_converter_new2.flow_converter import FlowConverter -from chatsky_ui.services.json_converter_new2.script_converter import ScriptConverter -from chatsky_ui.services.json_converter_new2.interface_converter import InterfaceConverter -from chatsky_ui.services.json_converter_new2.pipeline_converter import PipelineConverter +from chatsky_ui.services.json_converter.flow_converter import FlowConverter +from chatsky_ui.services.json_converter.interface_converter import InterfaceConverter +from chatsky_ui.services.json_converter.pipeline_converter import PipelineConverter +from chatsky_ui.services.json_converter.script_converter import ScriptConverter @pytest.fixture def chatsky_flow(chatsky_node): - return { - "test_flow": { - "test_node": chatsky_node - } - } + return {"test_flow": {"test_node": chatsky_node}} class TestFlowConverter: diff --git a/backend/chatsky_ui/tests/unit/test_logic_components.py b/backend/chatsky_ui/tests/unit/test_logic_components.py index b102b0fa..fdd231e6 100644 --- a/backend/chatsky_ui/tests/unit/test_logic_components.py +++ b/backend/chatsky_ui/tests/unit/test_logic_components.py @@ -1,16 +1,18 @@ +from pathlib import Path + import pytest -from chatsky_ui.services.json_converter_new2.logic_component_converter.condition_converter import ( + +from chatsky_ui.services.json_converter.logic_component_converter.condition_converter import ( + BadConditionException, CustomConditionConverter, SlotConditionConverter, - BadConditionException, ) -from chatsky_ui.services.json_converter_new2.logic_component_converter.response_converter import ( - TextResponseConverter, - CustomResponseConverter, +from chatsky_ui.services.json_converter.logic_component_converter.response_converter import ( BadResponseException, + CustomResponseConverter, + TextResponseConverter, ) -from chatsky_ui.services.json_converter_new2.logic_component_converter.service_replacer import store_custom_service -from pathlib import Path +from chatsky_ui.services.json_converter.logic_component_converter.service_replacer import store_custom_service @pytest.fixture diff --git a/backend/chatsky_ui/tests/unit/test_node_converer.py b/backend/chatsky_ui/tests/unit/test_node_converer.py index 882e3984..7bdb9a00 100644 --- a/backend/chatsky_ui/tests/unit/test_node_converer.py +++ b/backend/chatsky_ui/tests/unit/test_node_converer.py @@ -1,4 +1,4 @@ -from chatsky_ui.services.json_converter_new2.node_converter import InfoNodeConverter, LinkNodeConverter +from chatsky_ui.services.json_converter.node_converter import InfoNodeConverter, LinkNodeConverter class TestNodeConverter: diff --git a/backend/chatsky_ui/tests/unit/test_slots_converter.py b/backend/chatsky_ui/tests/unit/test_slots_converter.py index 3e54c2a1..feca20aa 100644 --- a/backend/chatsky_ui/tests/unit/test_slots_converter.py +++ b/backend/chatsky_ui/tests/unit/test_slots_converter.py @@ -1,8 +1,4 @@ -from chatsky_ui.services.json_converter_new2.slots_converter import ( - SlotsConverter, - RegexpSlotConverter, - GroupSlotConverter, -) +from chatsky_ui.services.json_converter.slots_converter import GroupSlotConverter, RegexpSlotConverter, SlotsConverter class TestSlotsConverter: diff --git a/backend/poetry.lock b/backend/poetry.lock index ff1e8617..81f0c1a9 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -413,12 +413,14 @@ files = [ [[package]] name = "chatsky" -version = "0.9.0" +version = "0.9.0.dev1" description = "Chatsky is a free and open-source software stack for creating chatbots, released under the terms of Apache License 2.0." optional = false -python-versions = "^3.9,!=3.9.7" -files = [] -develop = false +python-versions = "!=2.7.*,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,!=3.7.*,!=3.8.*,>=3.9" +files = [ + {file = "chatsky-0.9.0.dev1-py3-none-any.whl", hash = "sha256:b49acf9abaf5e12fcdd1f03fd47d8f1b9dc373a4fa2e8ece19961be03152b2e2"}, + {file = "chatsky-0.9.0.dev1.tar.gz", hash = "sha256:a5f7ac9e810095d34788f39f35825799da2857c7698caad1cd12a1c70ef7061c"}, +] [package.dependencies] colorama = "*" @@ -1530,13 +1532,13 @@ unidecode = ["Unidecode (>=1.1.1)"] [[package]] name = "python-telegram-bot" -version = "21.8" +version = "21.7" description = "We have made you a wrapper you can't refuse" optional = false python-versions = ">=3.9" files = [ - {file = "python_telegram_bot-21.8-py3-none-any.whl", hash = "sha256:2fea8e65d97e593f47666e7de81fb15bd517100504e98ca7cb399ee6ce4f3838"}, - {file = "python_telegram_bot-21.8.tar.gz", hash = "sha256:114437f194e32eee0651f25fb1ab1664b605e877ca33adf58547a599afe73b72"}, + {file = "python_telegram_bot-21.7-py3-none-any.whl", hash = "sha256:aff1d7245f1b0d4d12d41c9acff74e86d7100713c2204cd02ff17f8d80d18846"}, + {file = "python_telegram_bot-21.7.tar.gz", hash = "sha256:bc8537b77ae02531fc2ad440caafc023fd13f13cf19e592dfa1a9ff84988a012"}, ] [package.dependencies] @@ -2393,4 +2395,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9,!=3.9.7" -content-hash = "8539df9b57bdf437aebcc0ea06e63d3da12180a44a64282f95a5f903e7d0ab54" +content-hash = "a676df6948689fe5ff0e011484f12ecdde34add2dd2dfca1d290f1d8f8203674" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index 45427923..a089a25a 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "chatsky-ui" -version = "0.3.0" +version = "0.4.0" description = "Chatsky-UI is GUI for Chatsky Framework, that is a free and open-source software stack for creating chatbots, released under the terms of Apache License 2.0." license = "Apache-2.0" authors = [ @@ -20,7 +20,7 @@ typer = "^0.9.0" pydantic-settings = "^2.2.1" aiofiles = "^23.2.1" cookiecutter = "^2.6.0" -chatsky = {extras = ["yaml", "telegram"], git = "https://github.com/deeppavlov/chatsky.git", branch = "feat/add-docker-image"} +chatsky = {extras = ["yaml", "telegram"], version = "==0.9.0.dev1"} omegaconf = "^2.3.0" httpx = "^0.27.0" httpx-ws = "^0.6.0" diff --git a/bin/add_ui_to_toml.sh b/bin/add_ui_to_toml.sh deleted file mode 100755 index a0be2353..00000000 --- a/bin/add_ui_to_toml.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -# Find the latest version of the wheel file -VERSION=$(basename $(ls ../backend/dist/chatsky_ui-*.whl) | sed -E 's/chatsky_ui-([^-]+)-.*/\1/' | head -n 1) - -# Add the specific version to my project -poetry add ../backend/dist/chatsky_ui-$VERSION-py3-none-any.whl From 219345a90acca5ba1a9985bb651c9995ea684b5b Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 16 Dec 2024 18:52:21 +0800 Subject: [PATCH 40/41] update lock file --- backend/poetry.lock | 1659 +++++++++++++++++++++------------------- backend/pyproject.toml | 2 +- 2 files changed, 869 insertions(+), 792 deletions(-) diff --git a/backend/poetry.lock b/backend/poetry.lock index 81f0c1a9..f82da2e1 100644 --- a/backend/poetry.lock +++ b/backend/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.7.1 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 = "aiofiles" @@ -13,35 +13,35 @@ files = [ [[package]] name = "aiolimiter" -version = "1.1.1" +version = "1.2.1" description = "asyncio rate limiter, a leaky bucket implementation" optional = false python-versions = "<4.0,>=3.8" files = [ - {file = "aiolimiter-1.1.1-py3-none-any.whl", hash = "sha256:bf23dafbd1370e0816792fbcfb8fb95d5138c26e05f839fe058f5440bea006f5"}, - {file = "aiolimiter-1.1.1.tar.gz", hash = "sha256:4b5740c96ecf022d978379130514a26c18001e7450ba38adf19515cd0970f68f"}, + {file = "aiolimiter-1.2.1-py3-none-any.whl", hash = "sha256:d3f249e9059a20badcb56b61601a83556133655c11d1eb3dd3e04ff069e5f3c7"}, + {file = "aiolimiter-1.2.1.tar.gz", hash = "sha256:e02a37ea1a855d9e832252a105420ad4d15011505512a1a1d814647451b5cca9"}, ] [[package]] name = "alabaster" -version = "0.7.13" -description = "A configurable sidebar-enabled Sphinx theme" +version = "0.7.16" +description = "A light, configurable Sphinx theme" optional = false -python-versions = ">=3.6" +python-versions = ">=3.9" files = [ - {file = "alabaster-0.7.13-py3-none-any.whl", hash = "sha256:1ee19aca801bbabb5ba3f5f258e4422dfa86f82f3e9cefb0859b283cdd7f62a3"}, - {file = "alabaster-0.7.13.tar.gz", hash = "sha256:a27a4a084d5e690e16e01e03ad2b2e552c61a65469419b907243193de1a84ae2"}, + {file = "alabaster-0.7.16-py3-none-any.whl", hash = "sha256:b46733c07dce03ae4e150330b975c75737fa60f0a7c591b6c8bf4928a28e2c92"}, + {file = "alabaster-0.7.16.tar.gz", hash = "sha256:75a8b99c28a5dad50dd7f8ccdd447a121ddb3892da9e53d1ca5cca3106d58d65"}, ] [[package]] name = "annotated-types" -version = "0.6.0" +version = "0.7.0" description = "Reusable constraint types to use with typing.Annotated" optional = false python-versions = ">=3.8" files = [ - {file = "annotated_types-0.6.0-py3-none-any.whl", hash = "sha256:0641064de18ba7a25dee8f96403ebc39113d0cb953a01429249d5c7564666a43"}, - {file = "annotated_types-0.6.0.tar.gz", hash = "sha256:563339e807e53ffd9c267e99fc6d9ea23eb8443c08f112651963e24e22f84a5d"}, + {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]] @@ -56,25 +56,25 @@ files = [ [[package]] name = "anyio" -version = "4.3.0" +version = "4.7.0" description = "High level compatibility layer for multiple asynchronous event loop implementations" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "anyio-4.3.0-py3-none-any.whl", hash = "sha256:048e05d0f6caeed70d731f3db756d35dcc1f35747c8c403364a8332c630441b8"}, - {file = "anyio-4.3.0.tar.gz", hash = "sha256:f75253795a87df48568485fd18cdd2a3fa5c4f7c5be8e5e36637733fce06fed6"}, + {file = "anyio-4.7.0-py3-none-any.whl", hash = "sha256:ea60c3723ab42ba6fff7e8ccb0488c898ec538ff4df1f1d5e642c3601d07e352"}, + {file = "anyio-4.7.0.tar.gz", hash = "sha256:2f834749c602966b7d456a7567cafcb309f96482b5081d14ac93ccd457f9dd48"}, ] [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\""} +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} [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)"] +doc = ["Sphinx (>=7.4,<8.0)", "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", "truststore (>=0.9.1)", "uvloop (>=0.21)"] +trio = ["trio (>=0.26.1)"] [[package]] name = "apscheduler" @@ -125,13 +125,13 @@ test = ["dateparser (==1.*)", "pre-commit", "pytest", "pytest-cov", "pytest-mock [[package]] name = "astroid" -version = "3.2.2" +version = "3.3.6" description = "An abstract syntax tree for Python with inference support." optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "astroid-3.2.2-py3-none-any.whl", hash = "sha256:e8a0083b4bb28fcffb6207a3bfc9e5d0a68be951dd7e336d5dcf639c682388c0"}, - {file = "astroid-3.2.2.tar.gz", hash = "sha256:8ead48e31b92b2e217b6c9733a21afafe479d52d6e164dd25fb1a770c7c3cf94"}, + {file = "astroid-3.3.6-py3-none-any.whl", hash = "sha256:db676dc4f3ae6bfe31cda227dc60e03438378d7a896aec57422c95634e8d722f"}, + {file = "astroid-3.3.6.tar.gz", hash = "sha256:6aaea045f938c735ead292204afdb977a36e989522b7833ef6fea94de743f442"}, ] [package.dependencies] @@ -139,13 +139,13 @@ typing-extensions = {version = ">=4.0.0", markers = "python_version < \"3.11\""} [[package]] name = "babel" -version = "2.15.0" +version = "2.16.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"}, + {file = "babel-2.16.0-py3-none-any.whl", hash = "sha256:368b5b98b37c06b7daf6696391c3240c938b37767d4584413e8438c5c435fa8b"}, + {file = "babel-2.16.0.tar.gz", hash = "sha256:d1f3554ca26605fe173f3de0c65f750f5a42f924499bf134de6423582298e316"}, ] [package.extras] @@ -213,13 +213,13 @@ files = [ [[package]] name = "certifi" -version = "2024.2.2" +version = "2024.12.14" 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"}, + {file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"}, + {file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"}, ] [[package]] @@ -314,101 +314,116 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.0" 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"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"}, + {file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"}, + {file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"}, + {file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"}, + {file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"}, + {file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"}, + {file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"}, + {file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"}, + {file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"}, + {file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"}, ] [[package]] @@ -427,8 +442,8 @@ colorama = "*" eval_type_backport = "*" nest-asyncio = "*" pydantic = ">=2.0" -python-telegram-bot = {version = "~=21.3", extras = ["all"], optional = true} -pyyaml = {version = "*", optional = true} +python-telegram-bot = {version = ">=21.3,<22.0", extras = ["all"], optional = true, markers = "extra == \"telegram\""} +pyyaml = {version = "*", optional = true, markers = "extra == \"yaml\""} typing-extensions = "*" wrapt = "*" @@ -447,12 +462,6 @@ web-api = ["fastapi", "uvicorn"] yaml = ["pyyaml"] ydb = ["six", "ydb"] -[package.source] -type = "git" -url = "https://github.com/deeppavlov/chatsky.git" -reference = "feat/add-docker-image" -resolved_reference = "7e8f2615337d2308b71e256f469fc58ce52f6156" - [[package]] name = "click" version = "8.1.7" @@ -501,83 +510,73 @@ rich = "*" [[package]] name = "coverage" -version = "7.6.1" +version = "7.6.9" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "coverage-7.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b06079abebbc0e89e6163b8e8f0e16270124c154dc6e4a47b413dd538859af16"}, - {file = "coverage-7.6.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:cf4b19715bccd7ee27b6b120e7e9dd56037b9c0681dcc1adc9ba9db3d417fa36"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61c0abb4c85b095a784ef23fdd4aede7a2628478e7baba7c5e3deba61070a02"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fd21f6ae3f08b41004dfb433fa895d858f3f5979e7762d052b12aef444e29afc"}, - {file = "coverage-7.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f59d57baca39b32db42b83b2a7ba6f47ad9c394ec2076b084c3f029b7afca23"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a1ac0ae2b8bd743b88ed0502544847c3053d7171a3cff9228af618a068ed9c34"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e6a08c0be454c3b3beb105c0596ebdc2371fab6bb90c0c0297f4e58fd7e1012c"}, - {file = "coverage-7.6.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f5796e664fe802da4f57a168c85359a8fbf3eab5e55cd4e4569fbacecc903959"}, - {file = "coverage-7.6.1-cp310-cp310-win32.whl", hash = "sha256:7bb65125fcbef8d989fa1dd0e8a060999497629ca5b0efbca209588a73356232"}, - {file = "coverage-7.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:3115a95daa9bdba70aea750db7b96b37259a81a709223c8448fa97727d546fe0"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7dea0889685db8550f839fa202744652e87c60015029ce3f60e006f8c4462c93"}, - {file = "coverage-7.6.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed37bd3c3b063412f7620464a9ac1314d33100329f39799255fb8d3027da50d3"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d85f5e9a5f8b73e2350097c3756ef7e785f55bd71205defa0bfdaf96c31616ff"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9bc572be474cafb617672c43fe989d6e48d3c83af02ce8de73fff1c6bb3c198d"}, - {file = "coverage-7.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0420b573964c760df9e9e86d1a9a622d0d27f417e1a949a8a66dd7bcee7bc6"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1f4aa8219db826ce6be7099d559f8ec311549bfc4046f7f9fe9b5cea5c581c56"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:fc5a77d0c516700ebad189b587de289a20a78324bc54baee03dd486f0855d234"}, - {file = "coverage-7.6.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b48f312cca9621272ae49008c7f613337c53fadca647d6384cc129d2996d1133"}, - {file = "coverage-7.6.1-cp311-cp311-win32.whl", hash = "sha256:1125ca0e5fd475cbbba3bb67ae20bd2c23a98fac4e32412883f9bcbaa81c314c"}, - {file = "coverage-7.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:8ae539519c4c040c5ffd0632784e21b2f03fc1340752af711f33e5be83a9d6c6"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:95cae0efeb032af8458fc27d191f85d1717b1d4e49f7cb226cf526ff28179778"}, - {file = "coverage-7.6.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5621a9175cf9d0b0c84c2ef2b12e9f5f5071357c4d2ea6ca1cf01814f45d2391"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:260933720fdcd75340e7dbe9060655aff3af1f0c5d20f46b57f262ab6c86a5e8"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07e2ca0ad381b91350c0ed49d52699b625aab2b44b65e1b4e02fa9df0e92ad2d"}, - {file = "coverage-7.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c44fee9975f04b33331cb8eb272827111efc8930cfd582e0320613263ca849ca"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:877abb17e6339d96bf08e7a622d05095e72b71f8afd8a9fefc82cf30ed944163"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:3e0cadcf6733c09154b461f1ca72d5416635e5e4ec4e536192180d34ec160f8a"}, - {file = "coverage-7.6.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c3c02d12f837d9683e5ab2f3d9844dc57655b92c74e286c262e0fc54213c216d"}, - {file = "coverage-7.6.1-cp312-cp312-win32.whl", hash = "sha256:e05882b70b87a18d937ca6768ff33cc3f72847cbc4de4491c8e73880766718e5"}, - {file = "coverage-7.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:b5d7b556859dd85f3a541db6a4e0167b86e7273e1cdc973e5b175166bb634fdb"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:a4acd025ecc06185ba2b801f2de85546e0b8ac787cf9d3b06e7e2a69f925b106"}, - {file = "coverage-7.6.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a6d3adcf24b624a7b778533480e32434a39ad8fa30c315208f6d3e5542aeb6e9"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0c212c49b6c10e6951362f7c6df3329f04c2b1c28499563d4035d964ab8e08c"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6e81d7a3e58882450ec4186ca59a3f20a5d4440f25b1cff6f0902ad890e6748a"}, - {file = "coverage-7.6.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:78b260de9790fd81e69401c2dc8b17da47c8038176a79092a89cb2b7d945d060"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a78d169acd38300060b28d600344a803628c3fd585c912cacc9ea8790fe96862"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:2c09f4ce52cb99dd7505cd0fc8e0e37c77b87f46bc9c1eb03fe3bc9991085388"}, - {file = "coverage-7.6.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6878ef48d4227aace338d88c48738a4258213cd7b74fd9a3d4d7582bb1d8a155"}, - {file = "coverage-7.6.1-cp313-cp313-win32.whl", hash = "sha256:44df346d5215a8c0e360307d46ffaabe0f5d3502c8a1cefd700b34baf31d411a"}, - {file = "coverage-7.6.1-cp313-cp313-win_amd64.whl", hash = "sha256:8284cf8c0dd272a247bc154eb6c95548722dce90d098c17a883ed36e67cdb129"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d3296782ca4eab572a1a4eca686d8bfb00226300dcefdf43faa25b5242ab8a3e"}, - {file = "coverage-7.6.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:502753043567491d3ff6d08629270127e0c31d4184c4c8d98f92c26f65019962"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a89ecca80709d4076b95f89f308544ec8f7b4727e8a547913a35f16717856cb"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a318d68e92e80af8b00fa99609796fdbcdfef3629c77c6283566c6f02c6d6704"}, - {file = "coverage-7.6.1-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:13b0a73a0896988f053e4fbb7de6d93388e6dd292b0d87ee51d106f2c11b465b"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:4421712dbfc5562150f7554f13dde997a2e932a6b5f352edcce948a815efee6f"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:166811d20dfea725e2e4baa71fffd6c968a958577848d2131f39b60043400223"}, - {file = "coverage-7.6.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:225667980479a17db1048cb2bf8bfb39b8e5be8f164b8f6628b64f78a72cf9d3"}, - {file = "coverage-7.6.1-cp313-cp313t-win32.whl", hash = "sha256:170d444ab405852903b7d04ea9ae9b98f98ab6d7e63e1115e82620807519797f"}, - {file = "coverage-7.6.1-cp313-cp313t-win_amd64.whl", hash = "sha256:b9f222de8cded79c49bf184bdbc06630d4c58eec9459b939b4a690c82ed05657"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6db04803b6c7291985a761004e9060b2bca08da6d04f26a7f2294b8623a0c1a0"}, - {file = "coverage-7.6.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:f1adfc8ac319e1a348af294106bc6a8458a0f1633cc62a1446aebc30c5fa186a"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a95324a9de9650a729239daea117df21f4b9868ce32e63f8b650ebe6cef5595b"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b43c03669dc4618ec25270b06ecd3ee4fa94c7f9b3c14bae6571ca00ef98b0d3"}, - {file = "coverage-7.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8929543a7192c13d177b770008bc4e8119f2e1f881d563fc6b6305d2d0ebe9de"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:a09ece4a69cf399510c8ab25e0950d9cf2b42f7b3cb0374f95d2e2ff594478a6"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:9054a0754de38d9dbd01a46621636689124d666bad1936d76c0341f7d71bf569"}, - {file = "coverage-7.6.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:0dbde0f4aa9a16fa4d754356a8f2e36296ff4d83994b2c9d8398aa32f222f989"}, - {file = "coverage-7.6.1-cp38-cp38-win32.whl", hash = "sha256:da511e6ad4f7323ee5702e6633085fb76c2f893aaf8ce4c51a0ba4fc07580ea7"}, - {file = "coverage-7.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:3f1156e3e8f2872197af3840d8ad307a9dd18e615dc64d9ee41696f287c57ad8"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:abd5fd0db5f4dc9289408aaf34908072f805ff7792632250dcb36dc591d24255"}, - {file = "coverage-7.6.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:547f45fa1a93154bd82050a7f3cddbc1a7a4dd2a9bf5cb7d06f4ae29fe94eaf8"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:645786266c8f18a931b65bfcefdbf6952dd0dea98feee39bd188607a9d307ed2"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e0b2df163b8ed01d515807af24f63de04bebcecbd6c3bfeff88385789fdf75a"}, - {file = "coverage-7.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:609b06f178fe8e9f89ef676532760ec0b4deea15e9969bf754b37f7c40326dbc"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:702855feff378050ae4f741045e19a32d57d19f3e0676d589df0575008ea5004"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:2bdb062ea438f22d99cba0d7829c2ef0af1d768d1e4a4f528087224c90b132cb"}, - {file = "coverage-7.6.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9c56863d44bd1c4fe2abb8a4d6f5371d197f1ac0ebdee542f07f35895fc07f36"}, - {file = "coverage-7.6.1-cp39-cp39-win32.whl", hash = "sha256:6e2cd258d7d927d09493c8df1ce9174ad01b381d4729a9d8d4e38670ca24774c"}, - {file = "coverage-7.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:06a737c882bd26d0d6ee7269b20b12f14a8704807a01056c80bb881a4b2ce6ca"}, - {file = "coverage-7.6.1-pp38.pp39.pp310-none-any.whl", hash = "sha256:e9a6e0eb86070e8ccaedfbd9d38fec54864f3125ab95419970575b42af7541df"}, - {file = "coverage-7.6.1.tar.gz", hash = "sha256:953510dfb7b12ab69d20135a0662397f077c59b1e6379a768e97c59d852ee51d"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:85d9636f72e8991a1706b2b55b06c27545448baf9f6dbf51c4004609aacd7dcb"}, + {file = "coverage-7.6.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:608a7fd78c67bee8936378299a6cb9f5149bb80238c7a566fc3e6717a4e68710"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:96d636c77af18b5cb664ddf12dab9b15a0cfe9c0bde715da38698c8cea748bfa"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d75cded8a3cff93da9edc31446872d2997e327921d8eed86641efafd350e1df1"}, + {file = "coverage-7.6.9-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7b15f589593110ae767ce997775d645b47e5cbbf54fd322f8ebea6277466cec"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:44349150f6811b44b25574839b39ae35291f6496eb795b7366fef3bd3cf112d3"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:d891c136b5b310d0e702e186d70cd16d1119ea8927347045124cb286b29297e5"}, + {file = "coverage-7.6.9-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:db1dab894cc139f67822a92910466531de5ea6034ddfd2b11c0d4c6257168073"}, + {file = "coverage-7.6.9-cp310-cp310-win32.whl", hash = "sha256:41ff7b0da5af71a51b53f501a3bac65fb0ec311ebed1632e58fc6107f03b9198"}, + {file = "coverage-7.6.9-cp310-cp310-win_amd64.whl", hash = "sha256:35371f8438028fdccfaf3570b31d98e8d9eda8bb1d6ab9473f5a390969e98717"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:932fc826442132dde42ee52cf66d941f581c685a6313feebed358411238f60f9"}, + {file = "coverage-7.6.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:085161be5f3b30fd9b3e7b9a8c301f935c8313dcf928a07b116324abea2c1c2c"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ccc660a77e1c2bf24ddbce969af9447a9474790160cfb23de6be4fa88e3951c7"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c69e42c892c018cd3c8d90da61d845f50a8243062b19d228189b0224150018a9"}, + {file = "coverage-7.6.9-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0824a28ec542a0be22f60c6ac36d679e0e262e5353203bea81d44ee81fe9c6d4"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4401ae5fc52ad8d26d2a5d8a7428b0f0c72431683f8e63e42e70606374c311a1"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:98caba4476a6c8d59ec1eb00c7dd862ba9beca34085642d46ed503cc2d440d4b"}, + {file = "coverage-7.6.9-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ee5defd1733fd6ec08b168bd4f5387d5b322f45ca9e0e6c817ea6c4cd36313e3"}, + {file = "coverage-7.6.9-cp311-cp311-win32.whl", hash = "sha256:f2d1ec60d6d256bdf298cb86b78dd715980828f50c46701abc3b0a2b3f8a0dc0"}, + {file = "coverage-7.6.9-cp311-cp311-win_amd64.whl", hash = "sha256:0d59fd927b1f04de57a2ba0137166d31c1a6dd9e764ad4af552912d70428c92b"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:99e266ae0b5d15f1ca8d278a668df6f51cc4b854513daab5cae695ed7b721cf8"}, + {file = "coverage-7.6.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9901d36492009a0a9b94b20e52ebfc8453bf49bb2b27bca2c9706f8b4f5a554a"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:abd3e72dd5b97e3af4246cdada7738ef0e608168de952b837b8dd7e90341f015"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ff74026a461eb0660366fb01c650c1d00f833a086b336bdad7ab00cc952072b3"}, + {file = "coverage-7.6.9-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:65dad5a248823a4996724a88eb51d4b31587aa7aa428562dbe459c684e5787ae"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:22be16571504c9ccea919fcedb459d5ab20d41172056206eb2994e2ff06118a4"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:0f957943bc718b87144ecaee70762bc2bc3f1a7a53c7b861103546d3a403f0a6"}, + {file = "coverage-7.6.9-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ae1387db4aecb1f485fb70a6c0148c6cdaebb6038f1d40089b1fc84a5db556f"}, + {file = "coverage-7.6.9-cp312-cp312-win32.whl", hash = "sha256:1a330812d9cc7ac2182586f6d41b4d0fadf9be9049f350e0efb275c8ee8eb692"}, + {file = "coverage-7.6.9-cp312-cp312-win_amd64.whl", hash = "sha256:b12c6b18269ca471eedd41c1b6a1065b2f7827508edb9a7ed5555e9a56dcfc97"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:899b8cd4781c400454f2f64f7776a5d87bbd7b3e7f7bda0cb18f857bb1334664"}, + {file = "coverage-7.6.9-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:61f70dc68bd36810972e55bbbe83674ea073dd1dcc121040a08cdf3416c5349c"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a289d23d4c46f1a82d5db4abeb40b9b5be91731ee19a379d15790e53031c014"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7e216d8044a356fc0337c7a2a0536d6de07888d7bcda76febcb8adc50bdbbd00"}, + {file = "coverage-7.6.9-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c026eb44f744acaa2bda7493dad903aa5bf5fc4f2554293a798d5606710055d"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e77363e8425325384f9d49272c54045bbed2f478e9dd698dbc65dbc37860eb0a"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:777abfab476cf83b5177b84d7486497e034eb9eaea0d746ce0c1268c71652077"}, + {file = "coverage-7.6.9-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:447af20e25fdbe16f26e84eb714ba21d98868705cb138252d28bc400381f6ffb"}, + {file = "coverage-7.6.9-cp313-cp313-win32.whl", hash = "sha256:d872ec5aeb086cbea771c573600d47944eea2dcba8be5f3ee649bfe3cb8dc9ba"}, + {file = "coverage-7.6.9-cp313-cp313-win_amd64.whl", hash = "sha256:fd1213c86e48dfdc5a0cc676551db467495a95a662d2396ecd58e719191446e1"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:ba9e7484d286cd5a43744e5f47b0b3fb457865baf07bafc6bee91896364e1419"}, + {file = "coverage-7.6.9-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e5ea1cf0872ee455c03e5674b5bca5e3e68e159379c1af0903e89f5eba9ccc3a"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d10e07aa2b91835d6abec555ec8b2733347956991901eea6ffac295f83a30e4"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:13a9e2d3ee855db3dd6ea1ba5203316a1b1fd8eaeffc37c5b54987e61e4194ae"}, + {file = "coverage-7.6.9-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c38bf15a40ccf5619fa2fe8f26106c7e8e080d7760aeccb3722664c8656b030"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:d5275455b3e4627c8e7154feaf7ee0743c2e7af82f6e3b561967b1cca755a0be"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8f8770dfc6e2c6a2d4569f411015c8d751c980d17a14b0530da2d7f27ffdd88e"}, + {file = "coverage-7.6.9-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8d2dfa71665a29b153a9681edb1c8d9c1ea50dfc2375fb4dac99ea7e21a0bcd9"}, + {file = "coverage-7.6.9-cp313-cp313t-win32.whl", hash = "sha256:5e6b86b5847a016d0fbd31ffe1001b63355ed309651851295315031ea7eb5a9b"}, + {file = "coverage-7.6.9-cp313-cp313t-win_amd64.whl", hash = "sha256:97ddc94d46088304772d21b060041c97fc16bdda13c6c7f9d8fcd8d5ae0d8611"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:adb697c0bd35100dc690de83154627fbab1f4f3c0386df266dded865fc50a902"}, + {file = "coverage-7.6.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:be57b6d56e49c2739cdf776839a92330e933dd5e5d929966fbbd380c77f060be"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f1592791f8204ae9166de22ba7e6705fa4ebd02936c09436a1bb85aabca3e599"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4e12ae8cc979cf83d258acb5e1f1cf2f3f83524d1564a49d20b8bec14b637f08"}, + {file = "coverage-7.6.9-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5555cff66c4d3d6213a296b360f9e1a8e323e74e0426b6c10ed7f4d021e464"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b9389a429e0e5142e69d5bf4a435dd688c14478a19bb901735cdf75e57b13845"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:592ac539812e9b46046620341498caf09ca21023c41c893e1eb9dbda00a70cbf"}, + {file = "coverage-7.6.9-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a27801adef24cc30871da98a105f77995e13a25a505a0161911f6aafbd66e678"}, + {file = "coverage-7.6.9-cp39-cp39-win32.whl", hash = "sha256:8e3c3e38930cfb729cb8137d7f055e5a473ddaf1217966aa6238c88bd9fd50e6"}, + {file = "coverage-7.6.9-cp39-cp39-win_amd64.whl", hash = "sha256:e28bf44afa2b187cc9f41749138a64435bf340adfcacb5b2290c070ce99839d4"}, + {file = "coverage-7.6.9-pp39.pp310-none-any.whl", hash = "sha256:f3ca78518bc6bc92828cd11867b121891d75cae4ea9e908d72030609b996db1b"}, + {file = "coverage-7.6.9.tar.gz", hash = "sha256:4a8d8977b0c6ef5aeadcb644da9e69ae0dcfe66ec7f368c89c72e058bd71164d"}, ] [package.dependencies] @@ -637,13 +636,13 @@ test-randomorder = ["pytest-randomly"] [[package]] name = "dill" -version = "0.3.8" +version = "0.3.9" description = "serialize all of Python" optional = false python-versions = ">=3.8" files = [ - {file = "dill-0.3.8-py3-none-any.whl", hash = "sha256:c36ca9ffb54365bdd2f8eb3eff7d2a21237f8452b57ace88b1ac615b7e815bd7"}, - {file = "dill-0.3.8.tar.gz", hash = "sha256:3ebe3c479ad625c4553aca177444d89b486b1d84982eeacded644afc0cf797ca"}, + {file = "dill-0.3.9-py3-none-any.whl", hash = "sha256:468dff3b89520b474c0397703366b7b95eebe6303f108adf9b19da1f702be87a"}, + {file = "dill-0.3.9.tar.gz", hash = "sha256:81aa267dddf68cbfe8029c42ca9ec6a4ab3b22371d1c450abc54422577b4512c"}, ] [package.extras] @@ -652,13 +651,13 @@ profile = ["gprof2dot (>=2022.7.29)"] [[package]] name = "docutils" -version = "0.20.1" +version = "0.21.2" description = "Docutils -- Python Documentation Utilities" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "docutils-0.20.1-py3-none-any.whl", hash = "sha256:96f387a2c5562db4476f09f13bbab2192e764cac08ebbf3a34a95d9b1e4a59d6"}, - {file = "docutils-0.20.1.tar.gz", hash = "sha256:f08a4e276c3a1583a86dce3e34aba3fe04d02bba2dd51ed16106244e8a923e3b"}, + {file = "docutils-0.21.2-py3-none-any.whl", hash = "sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2"}, + {file = "docutils-0.21.2.tar.gz", hash = "sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f"}, ] [[package]] @@ -677,13 +676,13 @@ tests = ["pytest"] [[package]] name = "exceptiongroup" -version = "1.2.0" +version = "1.2.2" 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"}, + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, ] [package.extras] @@ -691,13 +690,13 @@ test = ["pytest (>=6)"] [[package]] name = "fastapi" -version = "0.110.1" +version = "0.110.3" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" optional = false python-versions = ">=3.8" files = [ - {file = "fastapi-0.110.1-py3-none-any.whl", hash = "sha256:5df913203c482f820d31f48e635e022f8cbfe7350e4830ef05a3163925b1addc"}, - {file = "fastapi-0.110.1.tar.gz", hash = "sha256:6feac43ec359dfe4f45b2c18ec8c94edb8dc2dfc461d417d9e626590c071baad"}, + {file = "fastapi-0.110.3-py3-none-any.whl", hash = "sha256:fd7600612f755e4050beb74001310b5a7e1796d149c2ee363124abdfa0289d32"}, + {file = "fastapi-0.110.3.tar.gz", hash = "sha256:555700b0159379e94fdbfc6bb66a0f1c43f4cf7060f25239af3d84b63a656626"}, ] [package.dependencies] @@ -706,7 +705,7 @@ starlette = ">=0.37.2,<0.38.0" typing-extensions = ">=4.8.0" [package.extras] -all = ["email-validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] +all = ["email_validator (>=2.0.0)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=2.11.2)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.7)", "pyyaml (>=5.3.1)", "ujson (>=4.0.1,!=4.0.2,!=4.1.0,!=4.2.0,!=4.3.0,!=5.0.0,!=5.1.0)", "uvicorn[standard] (>=0.12.0)"] [[package]] name = "flake8" @@ -795,13 +794,13 @@ files = [ [[package]] name = "httpcore" -version = "1.0.5" +version = "1.0.7" 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"}, + {file = "httpcore-1.0.7-py3-none-any.whl", hash = "sha256:a3fff8f43dc260d5bd363d9f9cf1830fa3a458b332856f34282de498ed420edd"}, + {file = "httpcore-1.0.7.tar.gz", hash = "sha256:8551cb62a169ec7162ac7be8d4817d561f60e08eaa485234898414bb5a8a0b4c"}, ] [package.dependencies] @@ -812,65 +811,72 @@ h11 = ">=0.13,<0.15" asyncio = ["anyio (>=4.0,<5.0)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] -trio = ["trio (>=0.22.0,<0.26.0)"] +trio = ["trio (>=0.22.0,<1.0)"] [[package]] name = "httptools" -version = "0.6.1" +version = "0.6.4" description = "A collection of framework independent HTTP protocol utils." optional = false python-versions = ">=3.8.0" files = [ - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d2f6c3c4cb1948d912538217838f6e9960bc4a521d7f9b323b3da579cd14532f"}, - {file = "httptools-0.6.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:00d5d4b68a717765b1fabfd9ca755bd12bf44105eeb806c03d1962acd9b8e563"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:639dc4f381a870c9ec860ce5c45921db50205a37cc3334e756269736ff0aac58"}, - {file = "httptools-0.6.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e57997ac7fb7ee43140cc03664de5f268813a481dff6245e0075925adc6aa185"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:0ac5a0ae3d9f4fe004318d64b8a854edd85ab76cffbf7ef5e32920faef62f142"}, - {file = "httptools-0.6.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:3f30d3ce413088a98b9db71c60a6ada2001a08945cb42dd65a9a9fe228627658"}, - {file = "httptools-0.6.1-cp310-cp310-win_amd64.whl", hash = "sha256:1ed99a373e327f0107cb513b61820102ee4f3675656a37a50083eda05dc9541b"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7a7ea483c1a4485c71cb5f38be9db078f8b0e8b4c4dc0210f531cdd2ddac1ef1"}, - {file = "httptools-0.6.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:85ed077c995e942b6f1b07583e4eb0a8d324d418954fc6af913d36db7c05a5a0"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8b0bb634338334385351a1600a73e558ce619af390c2b38386206ac6a27fecfc"}, - {file = "httptools-0.6.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9ceb2c957320def533671fc9c715a80c47025139c8d1f3797477decbc6edd2"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:4f0f8271c0a4db459f9dc807acd0eadd4839934a4b9b892f6f160e94da309837"}, - {file = "httptools-0.6.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:6a4f5ccead6d18ec072ac0b84420e95d27c1cdf5c9f1bc8fbd8daf86bd94f43d"}, - {file = "httptools-0.6.1-cp311-cp311-win_amd64.whl", hash = "sha256:5cceac09f164bcba55c0500a18fe3c47df29b62353198e4f37bbcc5d591172c3"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:75c8022dca7935cba14741a42744eee13ba05db00b27a4b940f0d646bd4d56d0"}, - {file = "httptools-0.6.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:48ed8129cd9a0d62cf4d1575fcf90fb37e3ff7d5654d3a5814eb3d55f36478c2"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f58e335a1402fb5a650e271e8c2d03cfa7cea46ae124649346d17bd30d59c90"}, - {file = "httptools-0.6.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:93ad80d7176aa5788902f207a4e79885f0576134695dfb0fefc15b7a4648d503"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:9bb68d3a085c2174c2477eb3ffe84ae9fb4fde8792edb7bcd09a1d8467e30a84"}, - {file = "httptools-0.6.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:b512aa728bc02354e5ac086ce76c3ce635b62f5fbc32ab7082b5e582d27867bb"}, - {file = "httptools-0.6.1-cp312-cp312-win_amd64.whl", hash = "sha256:97662ce7fb196c785344d00d638fc9ad69e18ee4bfb4000b35a52efe5adcc949"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:8e216a038d2d52ea13fdd9b9c9c7459fb80d78302b257828285eca1c773b99b3"}, - {file = "httptools-0.6.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:3e802e0b2378ade99cd666b5bffb8b2a7cc8f3d28988685dc300469ea8dd86cb"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4bd3e488b447046e386a30f07af05f9b38d3d368d1f7b4d8f7e10af85393db97"}, - {file = "httptools-0.6.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe467eb086d80217b7584e61313ebadc8d187a4d95bb62031b7bab4b205c3ba3"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3c3b214ce057c54675b00108ac42bacf2ab8f85c58e3f324a4e963bbc46424f4"}, - {file = "httptools-0.6.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8ae5b97f690badd2ca27cbf668494ee1b6d34cf1c464271ef7bfa9ca6b83ffaf"}, - {file = "httptools-0.6.1-cp38-cp38-win_amd64.whl", hash = "sha256:405784577ba6540fa7d6ff49e37daf104e04f4b4ff2d1ac0469eaa6a20fde084"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:95fb92dd3649f9cb139e9c56604cc2d7c7bf0fc2e7c8d7fbd58f96e35eddd2a3"}, - {file = "httptools-0.6.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:dcbab042cc3ef272adc11220517278519adf8f53fd3056d0e68f0a6f891ba94e"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0cf2372e98406efb42e93bfe10f2948e467edfd792b015f1b4ecd897903d3e8d"}, - {file = "httptools-0.6.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:678fcbae74477a17d103b7cae78b74800d795d702083867ce160fc202104d0da"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:e0b281cf5a125c35f7f6722b65d8542d2e57331be573e9e88bc8b0115c4a7a81"}, - {file = "httptools-0.6.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:95658c342529bba4e1d3d2b1a874db16c7cca435e8827422154c9da76ac4e13a"}, - {file = "httptools-0.6.1-cp39-cp39-win_amd64.whl", hash = "sha256:7ebaec1bf683e4bf5e9fbb49b8cc36da482033596a415b3e4ebab5a4c0d7ec5e"}, - {file = "httptools-0.6.1.tar.gz", hash = "sha256:c6e26c30455600b95d94b1b836085138e82f177351454ee841c148f93a9bad5a"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0"}, + {file = "httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1"}, + {file = "httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959"}, + {file = "httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4"}, + {file = "httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069"}, + {file = "httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975"}, + {file = "httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721"}, + {file = "httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988"}, + {file = "httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2"}, + {file = "httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1"}, + {file = "httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81"}, + {file = "httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f"}, + {file = "httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660"}, + {file = "httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3"}, + {file = "httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5"}, + {file = "httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0"}, + {file = "httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:d3f0d369e7ffbe59c4b6116a44d6a8eb4783aae027f2c0b366cf0aa964185dba"}, + {file = "httptools-0.6.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:94978a49b8f4569ad607cd4946b759d90b285e39c0d4640c6b36ca7a3ddf2efc"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40dc6a8e399e15ea525305a2ddba998b0af5caa2566bcd79dcbe8948181eeaff"}, + {file = "httptools-0.6.4-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ab9ba8dcf59de5181f6be44a77458e45a578fc99c31510b8c65b7d5acc3cf490"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:fc411e1c0a7dcd2f902c7c48cf079947a7e65b5485dea9decb82b9105ca71a43"}, + {file = "httptools-0.6.4-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:d54efd20338ac52ba31e7da78e4a72570cf729fac82bc31ff9199bedf1dc7440"}, + {file = "httptools-0.6.4-cp38-cp38-win_amd64.whl", hash = "sha256:df959752a0c2748a65ab5387d08287abf6779ae9165916fe053e68ae1fbdc47f"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:85797e37e8eeaa5439d33e556662cc370e474445d5fab24dcadc65a8ffb04003"}, + {file = "httptools-0.6.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:db353d22843cf1028f43c3651581e4bb49374d85692a85f95f7b9a130e1b2cab"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1ffd262a73d7c28424252381a5b854c19d9de5f56f075445d33919a637e3547"}, + {file = "httptools-0.6.4-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:703c346571fa50d2e9856a37d7cd9435a25e7fd15e236c397bf224afaa355fe9"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:aafe0f1918ed07b67c1e838f950b1c1fabc683030477e60b335649b8020e1076"}, + {file = "httptools-0.6.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:0e563e54979e97b6d13f1bbc05a96109923e76b901f786a5eae36e99c01237bd"}, + {file = "httptools-0.6.4-cp39-cp39-win_amd64.whl", hash = "sha256:b799de31416ecc589ad79dd85a0b2657a8fe39327944998dea368c1d4c9e55e6"}, + {file = "httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c"}, ] [package.extras] -test = ["Cython (>=0.29.24,<0.30.0)"] +test = ["Cython (>=0.29.24)"] [[package]] name = "httpx" -version = "0.27.0" +version = "0.27.2" 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"}, + {file = "httpx-0.27.2-py3-none-any.whl", hash = "sha256:7bb2708e112d8fdd7829cd4243970f0c223274051cb35ee80c03301ee29a3df0"}, + {file = "httpx-0.27.2.tar.gz", hash = "sha256:f7c2be1d2f3c3c3160d441802406b206c2b76f5947b11115e6df10c6c65e66c2"}, ] [package.dependencies] @@ -887,16 +893,17 @@ brotli = ["brotli", "brotlicffi"] cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] http2 = ["h2 (>=3,<5)"] socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] [[package]] name = "httpx-ws" -version = "0.6.0" +version = "0.6.2" description = "WebSockets support for HTTPX" optional = false python-versions = ">=3.8" files = [ - {file = "httpx_ws-0.6.0-py3-none-any.whl", hash = "sha256:437cfca94519a4e6ae06eb5573192df6c0da85c22b1a19cc1ea0b02b05a51d25"}, - {file = "httpx_ws-0.6.0.tar.gz", hash = "sha256:60218f531fb474a2143af38568f4b7d94ba356780973443365c8e2c87882bb8c"}, + {file = "httpx_ws-0.6.2-py3-none-any.whl", hash = "sha256:24f87427acb757ada200aeab016cc429fa0bc71b0730429c37634867194e305c"}, + {file = "httpx_ws-0.6.2.tar.gz", hash = "sha256:b07446b9067a30f1012fa9851fdfd14207012cd657c485565884f90553d0854c"}, ] [package.dependencies] @@ -918,15 +925,18 @@ files = [ [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "imagesize" version = "1.4.1" @@ -940,22 +950,26 @@ files = [ [[package]] name = "importlib-metadata" -version = "8.4.0" +version = "8.5.0" description = "Read metadata from Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "importlib_metadata-8.4.0-py3-none-any.whl", hash = "sha256:66f342cc6ac9818fc6ff340576acd24d65ba0b3efabb2b4ac08b598965a4a2f1"}, - {file = "importlib_metadata-8.4.0.tar.gz", hash = "sha256:9a547d3bc3608b025f93d403fdd1aae741c24fbb8314df4b155675742ce303c5"}, + {file = "importlib_metadata-8.5.0-py3-none-any.whl", hash = "sha256:45e54197d28b7a7f1559e60b95e7c567032b602131fbd588f1497f47880aa68b"}, + {file = "importlib_metadata-8.5.0.tar.gz", hash = "sha256:71522656f0abace1d072b9e5481a48f07c138e00f079c38c8f883823f9c26bd7"}, ] [package.dependencies] -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1)"] +cover = ["pytest-cov"] doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] perf = ["ipython"] -test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-perf (>=0.9.2)", "pytest-ruff (>=0.2.1)"] +test = ["flufl.flake8", "importlib-resources (>=1.3)", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] [[package]] name = "iniconfig" @@ -984,13 +998,13 @@ colors = ["colorama (>=0.4.6)"] [[package]] name = "jinja2" -version = "3.1.3" +version = "3.1.4" description = "A very fast and expressive template engine." optional = false python-versions = ">=3.7" files = [ - {file = "Jinja2-3.1.3-py3-none-any.whl", hash = "sha256:7d6d50dd97d52cbc355597bd845fabfbac3f551e1f99619e39a35ce8c370b5fa"}, - {file = "Jinja2-3.1.3.tar.gz", hash = "sha256:ac8bd6544d4bb2c9792bf3a159e80bba8fda7f07e81bc3aed565432d5925ba90"}, + {file = "jinja2-3.1.4-py3-none-any.whl", hash = "sha256:bc5dd2abb727a5319567b7a813e6a2e7318c39f4f487cfe6c89c6f9c7d25197d"}, + {file = "jinja2-3.1.4.tar.gz", hash = "sha256:4a3aee7acbbe7303aede8e9648d13b8bf88a429282aa6122a993f0ac800cb369"}, ] [package.dependencies] @@ -1025,71 +1039,72 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions"] [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" 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"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -1153,13 +1168,13 @@ PyYAML = ">=5.1.0" [[package]] name = "packaging" -version = "24.0" +version = "24.2" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"}, + {file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"}, ] [[package]] @@ -1175,28 +1190,29 @@ files = [ [[package]] name = "platformdirs" -version = "4.2.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +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.0-py3-none-any.whl", hash = "sha256:0614df2a2f37e1a662acbd8e2b25b92ccf8632929bc6d43467e17fe89c75e068"}, - {file = "platformdirs-4.2.0.tar.gz", hash = "sha256:ef0cc731df711022c174543cb70a9b5bd22e5a9337c8624ef2c2ceb8ddad8768"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [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)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" -version = "1.4.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.4.0-py3-none-any.whl", hash = "sha256:7db9f7b503d67d1c5b95f59773ebb58a8c1c288129a88665838012cfb07b8981"}, - {file = "pluggy-1.4.0.tar.gz", hash = "sha256:8c85c2876142a764e5b7548e7d9a0e0ddb46f5185161049a79b7e974454223be"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -1227,109 +1243,131 @@ files = [ [[package]] name = "pydantic" -version = "2.7.0" +version = "2.10.3" description = "Data validation using Python type hints" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic-2.7.0-py3-none-any.whl", hash = "sha256:9dee74a271705f14f9a1567671d144a851c675b072736f0a7b2608fd9e495352"}, - {file = "pydantic-2.7.0.tar.gz", hash = "sha256:b5ecdd42262ca2462e2624793551e80911a1e989f462910bb81aef974b4bb383"}, + {file = "pydantic-2.10.3-py3-none-any.whl", hash = "sha256:be04d85bbc7b65651c5f8e6b9976ed9c6f41782a55524cef079a34a0bb82144d"}, + {file = "pydantic-2.10.3.tar.gz", hash = "sha256:cb5ac360ce894ceacd69c403187900a02c4b20b693a9dd1d643e1effab9eadf9"}, ] [package.dependencies] -annotated-types = ">=0.4.0" -pydantic-core = "2.18.1" -typing-extensions = ">=4.6.1" +annotated-types = ">=0.6.0" +pydantic-core = "2.27.1" +typing-extensions = ">=4.12.2" [package.extras] email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata"] [[package]] name = "pydantic-core" -version = "2.18.1" +version = "2.27.1" description = "Core functionality for Pydantic validation and serialization" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:ee9cf33e7fe14243f5ca6977658eb7d1042caaa66847daacbd2117adb258b226"}, - {file = "pydantic_core-2.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b7bbb97d82659ac8b37450c60ff2e9f97e4eb0f8a8a3645a5568b9334b08b50"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df4249b579e75094f7e9bb4bd28231acf55e308bf686b952f43100a5a0be394c"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d0491006a6ad20507aec2be72e7831a42efc93193d2402018007ff827dc62926"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2ae80f72bb7a3e397ab37b53a2b49c62cc5496412e71bc4f1277620a7ce3f52b"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:58aca931bef83217fca7a390e0486ae327c4af9c3e941adb75f8772f8eeb03a1"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be91ad664fc9245404a789d60cba1e91c26b1454ba136d2a1bf0c2ac0c0505a"}, - {file = "pydantic_core-2.18.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:667880321e916a8920ef49f5d50e7983792cf59f3b6079f3c9dac2b88a311d17"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:f7054fdc556f5421f01e39cbb767d5ec5c1139ea98c3e5b350e02e62201740c7"}, - {file = "pydantic_core-2.18.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:030e4f9516f9947f38179249778709a460a3adb516bf39b5eb9066fcfe43d0e6"}, - {file = "pydantic_core-2.18.1-cp310-none-win32.whl", hash = "sha256:2e91711e36e229978d92642bfc3546333a9127ecebb3f2761372e096395fc649"}, - {file = "pydantic_core-2.18.1-cp310-none-win_amd64.whl", hash = "sha256:9a29726f91c6cb390b3c2338f0df5cd3e216ad7a938762d11c994bb37552edb0"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:9ece8a49696669d483d206b4474c367852c44815fca23ac4e48b72b339807f80"}, - {file = "pydantic_core-2.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a5d83efc109ceddb99abd2c1316298ced2adb4570410defe766851a804fcd5b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5f7973c381283783cd1043a8c8f61ea5ce7a3a58b0369f0ee0ee975eaf2f2a1b"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:54c7375c62190a7845091f521add19b0f026bcf6ae674bdb89f296972272e86d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dd63cec4e26e790b70544ae5cc48d11b515b09e05fdd5eff12e3195f54b8a586"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:561cf62c8a3498406495cfc49eee086ed2bb186d08bcc65812b75fda42c38294"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68717c38a68e37af87c4da20e08f3e27d7e4212e99e96c3d875fbf3f4812abfc"}, - {file = "pydantic_core-2.18.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2d5728e93d28a3c63ee513d9ffbac9c5989de8c76e049dbcb5bfe4b923a9739d"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f0f17814c505f07806e22b28856c59ac80cee7dd0fbb152aed273e116378f519"}, - {file = "pydantic_core-2.18.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d816f44a51ba5175394bc6c7879ca0bd2be560b2c9e9f3411ef3a4cbe644c2e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win32.whl", hash = "sha256:09f03dfc0ef8c22622eaa8608caa4a1e189cfb83ce847045eca34f690895eccb"}, - {file = "pydantic_core-2.18.1-cp311-none-win_amd64.whl", hash = "sha256:27f1009dc292f3b7ca77feb3571c537276b9aad5dd4efb471ac88a8bd09024e9"}, - {file = "pydantic_core-2.18.1-cp311-none-win_arm64.whl", hash = "sha256:48dd883db92e92519201f2b01cafa881e5f7125666141a49ffba8b9facc072b0"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b6b0e4912030c6f28bcb72b9ebe4989d6dc2eebcd2a9cdc35fefc38052dd4fe8"}, - {file = "pydantic_core-2.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f3202a429fe825b699c57892d4371c74cc3456d8d71b7f35d6028c96dfecad31"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a3982b0a32d0a88b3907e4b0dc36809fda477f0757c59a505d4e9b455f384b8b"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:25595ac311f20e5324d1941909b0d12933f1fd2171075fcff763e90f43e92a0d"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:14fe73881cf8e4cbdaded8ca0aa671635b597e42447fec7060d0868b52d074e6"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca976884ce34070799e4dfc6fbd68cb1d181db1eefe4a3a94798ddfb34b8867f"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:684d840d2c9ec5de9cb397fcb3f36d5ebb6fa0d94734f9886032dd796c1ead06"}, - {file = "pydantic_core-2.18.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:54764c083bbe0264f0f746cefcded6cb08fbbaaf1ad1d78fb8a4c30cff999a90"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:201713f2f462e5c015b343e86e68bd8a530a4f76609b33d8f0ec65d2b921712a"}, - {file = "pydantic_core-2.18.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:fd1a9edb9dd9d79fbeac1ea1f9a8dd527a6113b18d2e9bcc0d541d308dae639b"}, - {file = "pydantic_core-2.18.1-cp312-none-win32.whl", hash = "sha256:d5e6b7155b8197b329dc787356cfd2684c9d6a6b1a197f6bbf45f5555a98d411"}, - {file = "pydantic_core-2.18.1-cp312-none-win_amd64.whl", hash = "sha256:9376d83d686ec62e8b19c0ac3bf8d28d8a5981d0df290196fb6ef24d8a26f0d6"}, - {file = "pydantic_core-2.18.1-cp312-none-win_arm64.whl", hash = "sha256:c562b49c96906b4029b5685075fe1ebd3b5cc2601dfa0b9e16c2c09d6cbce048"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:3e352f0191d99fe617371096845070dee295444979efb8f27ad941227de6ad09"}, - {file = "pydantic_core-2.18.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:c0295d52b012cbe0d3059b1dba99159c3be55e632aae1999ab74ae2bd86a33d7"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:56823a92075780582d1ffd4489a2e61d56fd3ebb4b40b713d63f96dd92d28144"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:dd3f79e17b56741b5177bcc36307750d50ea0698df6aa82f69c7db32d968c1c2"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:38a5024de321d672a132b1834a66eeb7931959c59964b777e8f32dbe9523f6b1"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d2ce426ee691319d4767748c8e0895cfc56593d725594e415f274059bcf3cb76"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2adaeea59849ec0939af5c5d476935f2bab4b7f0335b0110f0f069a41024278e"}, - {file = "pydantic_core-2.18.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9b6431559676a1079eac0f52d6d0721fb8e3c5ba43c37bc537c8c83724031feb"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:85233abb44bc18d16e72dc05bf13848a36f363f83757541f1a97db2f8d58cfd9"}, - {file = "pydantic_core-2.18.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:641a018af4fe48be57a2b3d7a1f0f5dbca07c1d00951d3d7463f0ac9dac66622"}, - {file = "pydantic_core-2.18.1-cp38-none-win32.whl", hash = "sha256:63d7523cd95d2fde0d28dc42968ac731b5bb1e516cc56b93a50ab293f4daeaad"}, - {file = "pydantic_core-2.18.1-cp38-none-win_amd64.whl", hash = "sha256:907a4d7720abfcb1c81619863efd47c8a85d26a257a2dbebdb87c3b847df0278"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:aad17e462f42ddbef5984d70c40bfc4146c322a2da79715932cd8976317054de"}, - {file = "pydantic_core-2.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:94b9769ba435b598b547c762184bcfc4783d0d4c7771b04a3b45775c3589ca44"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80e0e57cc704a52fb1b48f16d5b2c8818da087dbee6f98d9bf19546930dc64b5"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:76b86e24039c35280ceee6dce7e62945eb93a5175d43689ba98360ab31eebc4a"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12a05db5013ec0ca4a32cc6433f53faa2a014ec364031408540ba858c2172bb0"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:250ae39445cb5475e483a36b1061af1bc233de3e9ad0f4f76a71b66231b07f88"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a32204489259786a923e02990249c65b0f17235073149d0033efcebe80095570"}, - {file = "pydantic_core-2.18.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6395a4435fa26519fd96fdccb77e9d00ddae9dd6c742309bd0b5610609ad7fb2"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:2533ad2883f001efa72f3d0e733fb846710c3af6dcdd544fe5bf14fa5fe2d7db"}, - {file = "pydantic_core-2.18.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:b560b72ed4816aee52783c66854d96157fd8175631f01ef58e894cc57c84f0f6"}, - {file = "pydantic_core-2.18.1-cp39-none-win32.whl", hash = "sha256:582cf2cead97c9e382a7f4d3b744cf0ef1a6e815e44d3aa81af3ad98762f5a9b"}, - {file = "pydantic_core-2.18.1-cp39-none-win_amd64.whl", hash = "sha256:ca71d501629d1fa50ea7fa3b08ba884fe10cefc559f5c6c8dfe9036c16e8ae89"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:e178e5b66a06ec5bf51668ec0d4ac8cfb2bdcb553b2c207d58148340efd00143"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:72722ce529a76a4637a60be18bd789d8fb871e84472490ed7ddff62d5fed620d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2fe0c1ce5b129455e43f941f7a46f61f3d3861e571f2905d55cdbb8b5c6f5e2c"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4284c621f06a72ce2cb55f74ea3150113d926a6eb78ab38340c08f770eb9b4d"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1a0c3e718f4e064efde68092d9d974e39572c14e56726ecfaeebbe6544521f47"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2027493cc44c23b598cfaf200936110433d9caa84e2c6cf487a83999638a96ac"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:76909849d1a6bffa5a07742294f3fa1d357dc917cb1fe7b470afbc3a7579d539"}, - {file = "pydantic_core-2.18.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:ee7ccc7fb7e921d767f853b47814c3048c7de536663e82fbc37f5eb0d532224b"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:ee2794111c188548a4547eccc73a6a8527fe2af6cf25e1a4ebda2fd01cdd2e60"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a139fe9f298dc097349fb4f28c8b81cc7a202dbfba66af0e14be5cfca4ef7ce5"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d074b07a10c391fc5bbdcb37b2f16f20fcd9e51e10d01652ab298c0d07908ee2"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c69567ddbac186e8c0aadc1f324a60a564cfe25e43ef2ce81bcc4b8c3abffbae"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf1c7b78cddb5af00971ad5294a4583188bda1495b13760d9f03c9483bb6203"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:2684a94fdfd1b146ff10689c6e4e815f6a01141781c493b97342cdc5b06f4d5d"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:73c1bc8a86a5c9e8721a088df234265317692d0b5cd9e86e975ce3bc3db62a59"}, - {file = "pydantic_core-2.18.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:e60defc3c15defb70bb38dd605ff7e0fae5f6c9c7cbfe0ad7868582cb7e844a6"}, - {file = "pydantic_core-2.18.1.tar.gz", hash = "sha256:de9d3e8717560eb05e28739d1b35e4eac2e458553a52a301e51352a7ffc86a35"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:71a5e35c75c021aaf400ac048dacc855f000bdfed91614b4a726f7432f1f3d6a"}, + {file = "pydantic_core-2.27.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f82d068a2d6ecfc6e054726080af69a6764a10015467d7d7b9f66d6ed5afa23b"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:121ceb0e822f79163dd4699e4c54f5ad38b157084d97b34de8b232bcaad70278"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4603137322c18eaf2e06a4495f426aa8d8388940f3c457e7548145011bb68e05"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a33cd6ad9017bbeaa9ed78a2e0752c5e250eafb9534f308e7a5f7849b0b1bfb4"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:15cc53a3179ba0fcefe1e3ae50beb2784dede4003ad2dfd24f81bba4b23a454f"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45d9c5eb9273aa50999ad6adc6be5e0ecea7e09dbd0d31bd0c65a55a2592ca08"}, + {file = "pydantic_core-2.27.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8bf7b66ce12a2ac52d16f776b31d16d91033150266eb796967a7e4621707e4f6"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:655d7dd86f26cb15ce8a431036f66ce0318648f8853d709b4167786ec2fa4807"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:5556470f1a2157031e676f776c2bc20acd34c1990ca5f7e56f1ebf938b9ab57c"}, + {file = "pydantic_core-2.27.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:f69ed81ab24d5a3bd93861c8c4436f54afdf8e8cc421562b0c7504cf3be58206"}, + {file = "pydantic_core-2.27.1-cp310-none-win32.whl", hash = "sha256:f5a823165e6d04ccea61a9f0576f345f8ce40ed533013580e087bd4d7442b52c"}, + {file = "pydantic_core-2.27.1-cp310-none-win_amd64.whl", hash = "sha256:57866a76e0b3823e0b56692d1a0bf722bffb324839bb5b7226a7dbd6c9a40b17"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ac3b20653bdbe160febbea8aa6c079d3df19310d50ac314911ed8cc4eb7f8cb8"}, + {file = "pydantic_core-2.27.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a5a8e19d7c707c4cadb8c18f5f60c843052ae83c20fa7d44f41594c644a1d330"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f7059ca8d64fea7f238994c97d91f75965216bcbe5f695bb44f354893f11d52"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:bed0f8a0eeea9fb72937ba118f9db0cb7e90773462af7962d382445f3005e5a4"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a3cb37038123447cf0f3ea4c74751f6a9d7afef0eb71aa07bf5f652b5e6a132c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:84286494f6c5d05243456e04223d5a9417d7f443c3b76065e75001beb26f88de"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acc07b2cfc5b835444b44a9956846b578d27beeacd4b52e45489e93276241025"}, + {file = "pydantic_core-2.27.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4fefee876e07a6e9aad7a8c8c9f85b0cdbe7df52b8a9552307b09050f7512c7e"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:258c57abf1188926c774a4c94dd29237e77eda19462e5bb901d88adcab6af919"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:35c14ac45fcfdf7167ca76cc80b2001205a8d5d16d80524e13508371fb8cdd9c"}, + {file = "pydantic_core-2.27.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:d1b26e1dff225c31897696cab7d4f0a315d4c0d9e8666dbffdb28216f3b17fdc"}, + {file = "pydantic_core-2.27.1-cp311-none-win32.whl", hash = "sha256:2cdf7d86886bc6982354862204ae3b2f7f96f21a3eb0ba5ca0ac42c7b38598b9"}, + {file = "pydantic_core-2.27.1-cp311-none-win_amd64.whl", hash = "sha256:3af385b0cee8df3746c3f406f38bcbfdc9041b5c2d5ce3e5fc6637256e60bbc5"}, + {file = "pydantic_core-2.27.1-cp311-none-win_arm64.whl", hash = "sha256:81f2ec23ddc1b476ff96563f2e8d723830b06dceae348ce02914a37cb4e74b89"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9cbd94fc661d2bab2bc702cddd2d3370bbdcc4cd0f8f57488a81bcce90c7a54f"}, + {file = "pydantic_core-2.27.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5f8c4718cd44ec1580e180cb739713ecda2bdee1341084c1467802a417fe0f02"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:15aae984e46de8d376df515f00450d1522077254ef6b7ce189b38ecee7c9677c"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1ba5e3963344ff25fc8c40da90f44b0afca8cfd89d12964feb79ac1411a260ac"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:992cea5f4f3b29d6b4f7f1726ed8ee46c8331c6b4eed6db5b40134c6fe1768bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0325336f348dbee6550d129b1627cb8f5351a9dc91aad141ffb96d4937bd9529"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7597c07fbd11515f654d6ece3d0e4e5093edc30a436c63142d9a4b8e22f19c35"}, + {file = "pydantic_core-2.27.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3bbd5d8cc692616d5ef6fbbbd50dbec142c7e6ad9beb66b78a96e9c16729b089"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:dc61505e73298a84a2f317255fcc72b710b72980f3a1f670447a21efc88f8381"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:e1f735dc43da318cad19b4173dd1ffce1d84aafd6c9b782b3abc04a0d5a6f5bb"}, + {file = "pydantic_core-2.27.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:f4e5658dbffe8843a0f12366a4c2d1c316dbe09bb4dfbdc9d2d9cd6031de8aae"}, + {file = "pydantic_core-2.27.1-cp312-none-win32.whl", hash = "sha256:672ebbe820bb37988c4d136eca2652ee114992d5d41c7e4858cdd90ea94ffe5c"}, + {file = "pydantic_core-2.27.1-cp312-none-win_amd64.whl", hash = "sha256:66ff044fd0bb1768688aecbe28b6190f6e799349221fb0de0e6f4048eca14c16"}, + {file = "pydantic_core-2.27.1-cp312-none-win_arm64.whl", hash = "sha256:9a3b0793b1bbfd4146304e23d90045f2a9b5fd5823aa682665fbdaf2a6c28f3e"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f216dbce0e60e4d03e0c4353c7023b202d95cbaeff12e5fd2e82ea0a66905073"}, + {file = "pydantic_core-2.27.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a2e02889071850bbfd36b56fd6bc98945e23670773bc7a76657e90e6b6603c08"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42b0e23f119b2b456d07ca91b307ae167cc3f6c846a7b169fca5326e32fdc6cf"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:764be71193f87d460a03f1f7385a82e226639732214b402f9aa61f0d025f0737"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1c00666a3bd2f84920a4e94434f5974d7bbc57e461318d6bb34ce9cdbbc1f6b2"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ccaa88b24eebc0f849ce0a4d09e8a408ec5a94afff395eb69baf868f5183107"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c65af9088ac534313e1963443d0ec360bb2b9cba6c2909478d22c2e363d98a51"}, + {file = "pydantic_core-2.27.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:206b5cf6f0c513baffaeae7bd817717140770c74528f3e4c3e1cec7871ddd61a"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:062f60e512fc7fff8b8a9d680ff0ddaaef0193dba9fa83e679c0c5f5fbd018bc"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:a0697803ed7d4af5e4c1adf1670af078f8fcab7a86350e969f454daf598c4960"}, + {file = "pydantic_core-2.27.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:58ca98a950171f3151c603aeea9303ef6c235f692fe555e883591103da709b23"}, + {file = "pydantic_core-2.27.1-cp313-none-win32.whl", hash = "sha256:8065914ff79f7eab1599bd80406681f0ad08f8e47c880f17b416c9f8f7a26d05"}, + {file = "pydantic_core-2.27.1-cp313-none-win_amd64.whl", hash = "sha256:ba630d5e3db74c79300d9a5bdaaf6200172b107f263c98a0539eeecb857b2337"}, + {file = "pydantic_core-2.27.1-cp313-none-win_arm64.whl", hash = "sha256:45cf8588c066860b623cd11c4ba687f8d7175d5f7ef65f7129df8a394c502de5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:5897bec80a09b4084aee23f9b73a9477a46c3304ad1d2d07acca19723fb1de62"}, + {file = "pydantic_core-2.27.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d0165ab2914379bd56908c02294ed8405c252250668ebcb438a55494c69f44ab"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b9af86e1d8e4cfc82c2022bfaa6f459381a50b94a29e95dcdda8442d6d83864"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5f6c8a66741c5f5447e047ab0ba7a1c61d1e95580d64bce852e3df1f895c4067"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a42d6a8156ff78981f8aa56eb6394114e0dedb217cf8b729f438f643608cbcd"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64c65f40b4cd8b0e049a8edde07e38b476da7e3aaebe63287c899d2cff253fa5"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdcf339322a3fae5cbd504edcefddd5a50d9ee00d968696846f089b4432cf78"}, + {file = "pydantic_core-2.27.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bf99c8404f008750c846cb4ac4667b798a9f7de673ff719d705d9b2d6de49c5f"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:8f1edcea27918d748c7e5e4d917297b2a0ab80cad10f86631e488b7cddf76a36"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_armv7l.whl", hash = "sha256:159cac0a3d096f79ab6a44d77a961917219707e2a130739c64d4dd46281f5c2a"}, + {file = "pydantic_core-2.27.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:029d9757eb621cc6e1848fa0b0310310de7301057f623985698ed7ebb014391b"}, + {file = "pydantic_core-2.27.1-cp38-none-win32.whl", hash = "sha256:a28af0695a45f7060e6f9b7092558a928a28553366519f64083c63a44f70e618"}, + {file = "pydantic_core-2.27.1-cp38-none-win_amd64.whl", hash = "sha256:2d4567c850905d5eaaed2f7a404e61012a51caf288292e016360aa2b96ff38d4"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:e9386266798d64eeb19dd3677051f5705bf873e98e15897ddb7d76f477131967"}, + {file = "pydantic_core-2.27.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4228b5b646caa73f119b1ae756216b59cc6e2267201c27d3912b592c5e323b60"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0b3dfe500de26c52abe0477dde16192ac39c98f05bf2d80e76102d394bd13854"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:aee66be87825cdf72ac64cb03ad4c15ffef4143dbf5c113f64a5ff4f81477bf9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b748c44bb9f53031c8cbc99a8a061bc181c1000c60a30f55393b6e9c45cc5bd"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ca038c7f6a0afd0b2448941b6ef9d5e1949e999f9e5517692eb6da58e9d44be"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e0bd57539da59a3e4671b90a502da9a28c72322a4f17866ba3ac63a82c4498e"}, + {file = "pydantic_core-2.27.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ac6c2c45c847bbf8f91930d88716a0fb924b51e0c6dad329b793d670ec5db792"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b94d4ba43739bbe8b0ce4262bcc3b7b9f31459ad120fb595627eaeb7f9b9ca01"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:00e6424f4b26fe82d44577b4c842d7df97c20be6439e8e685d0d715feceb9fb9"}, + {file = "pydantic_core-2.27.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:38de0a70160dd97540335b7ad3a74571b24f1dc3ed33f815f0880682e6880131"}, + {file = "pydantic_core-2.27.1-cp39-none-win32.whl", hash = "sha256:7ccebf51efc61634f6c2344da73e366c75e735960b5654b63d7e6f69a5885fa3"}, + {file = "pydantic_core-2.27.1-cp39-none-win_amd64.whl", hash = "sha256:a57847b090d7892f123726202b7daa20df6694cbd583b67a592e856bff603d6c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3fa80ac2bd5856580e242dbc202db873c60a01b20309c8319b5c5986fbe53ce6"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d950caa237bb1954f1b8c9227b5065ba6875ac9771bb8ec790d956a699b78676"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0e4216e64d203e39c62df627aa882f02a2438d18a5f21d7f721621f7a5d3611d"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02a3d637bd387c41d46b002f0e49c52642281edacd2740e5a42f7017feea3f2c"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:161c27ccce13b6b0c8689418da3885d3220ed2eae2ea5e9b2f7f3d48f1d52c27"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:19910754e4cc9c63bc1c7f6d73aa1cfee82f42007e407c0f413695c2f7ed777f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:e173486019cc283dc9778315fa29a363579372fe67045e971e89b6365cc035ed"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:af52d26579b308921b73b956153066481f064875140ccd1dfd4e77db89dbb12f"}, + {file = "pydantic_core-2.27.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:981fb88516bd1ae8b0cbbd2034678a39dedc98752f264ac9bc5839d3923fa04c"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5fde892e6c697ce3e30c61b239330fc5d569a71fefd4eb6512fc6caec9dd9e2f"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:816f5aa087094099fff7edabb5e01cc370eb21aa1a1d44fe2d2aefdfb5599b31"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c10c309e18e443ddb108f0ef64e8729363adbfd92d6d57beec680f6261556f3"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98476c98b02c8e9b2eec76ac4156fd006628b1b2d0ef27e548ffa978393fd154"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c3027001c28434e7ca5a6e1e527487051136aa81803ac812be51802150d880dd"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:7699b1df36a48169cdebda7ab5a2bac265204003f153b4bd17276153d997670a"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1c39b07d90be6b48968ddc8c19e7585052088fd7ec8d568bb31ff64c70ae3c97"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:46ccfe3032b3915586e469d4972973f893c0a2bb65669194a5bdea9bacc088c2"}, + {file = "pydantic_core-2.27.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:62ba45e21cf6571d7f716d903b5b7b6d2617e2d5d67c0923dc47b9d41369f840"}, + {file = "pydantic_core-2.27.1.tar.gz", hash = "sha256:62a763352879b84aa31058fc931884055fd75089cccbd9d58bb6afd01141b235"}, ] [package.dependencies] @@ -1337,20 +1375,21 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydantic-settings" -version = "2.2.1" +version = "2.7.0" description = "Settings management using Pydantic" optional = false python-versions = ">=3.8" files = [ - {file = "pydantic_settings-2.2.1-py3-none-any.whl", hash = "sha256:0235391d26db4d2190cb9b31051c4b46882d28a51533f97440867f012d4da091"}, - {file = "pydantic_settings-2.2.1.tar.gz", hash = "sha256:00b9f6a5e95553590434c0fa01ead0b216c3e10bc54ae02e37f359948643c5ed"}, + {file = "pydantic_settings-2.7.0-py3-none-any.whl", hash = "sha256:e00c05d5fa6cbbb227c84bd7487c5c1065084119b750df7c8c1a554aed236eb5"}, + {file = "pydantic_settings-2.7.0.tar.gz", hash = "sha256:ac4bfd4a36831a48dbf8b2d9325425b549a0a6f18cea118436d728eb4f1c4d66"}, ] [package.dependencies] -pydantic = ">=2.3.0" +pydantic = ">=2.7.0" python-dotenv = ">=0.21.0" [package.extras] +azure-key-vault = ["azure-identity (>=1.16.0)", "azure-keyvault-secrets (>=4.8.0)"] toml = ["tomli (>=2.0.1)"] yaml = ["pyyaml (>=6.0.1)"] @@ -1367,32 +1406,31 @@ files = [ [[package]] name = "pygments" -version = "2.17.2" +version = "2.18.0" description = "Pygments is a syntax highlighting package written in Python." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pygments-2.17.2-py3-none-any.whl", hash = "sha256:b27c2826c47d0f3219f29554824c30c5e8945175d888647acd804ddd04af846c"}, - {file = "pygments-2.17.2.tar.gz", hash = "sha256:da46cec9fd2de5be3a8a784f434e4c4ab670b4ff54d605c4c2717e9d49c4c367"}, + {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, + {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, ] [package.extras] -plugins = ["importlib-metadata"] windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pylint" -version = "3.2.3" +version = "3.3.2" description = "python code static checker" optional = false -python-versions = ">=3.8.0" +python-versions = ">=3.9.0" files = [ - {file = "pylint-3.2.3-py3-none-any.whl", hash = "sha256:b3d7d2708a3e04b4679e02d99e72329a8b7ee8afb8d04110682278781f889fa8"}, - {file = "pylint-3.2.3.tar.gz", hash = "sha256:02f6c562b215582386068d52a30f520d84fdbcf2a95fc7e855b816060d048b60"}, + {file = "pylint-3.3.2-py3-none-any.whl", hash = "sha256:77f068c287d49b8683cd7c6e624243c74f92890f767f106ffa1ddf3c0a54cb7a"}, + {file = "pylint-3.3.2.tar.gz", hash = "sha256:9ec054ec992cd05ad30a6df1676229739a73f8feeabf3912c995d17601052b01"}, ] [package.dependencies] -astroid = ">=3.2.2,<=3.3.0-dev0" +astroid = ">=3.3.5,<=3.4.0-dev0" colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} dill = [ {version = ">=0.2", markers = "python_version < \"3.11\""}, @@ -1412,13 +1450,13 @@ testutils = ["gitpython (>3)"] [[package]] name = "pytest" -version = "8.1.1" +version = "8.3.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-8.1.1-py3-none-any.whl", hash = "sha256:2a8386cfc11fa9d2c50ee7b2a57e7d898ef90470a7a34c4b949ff59662bb78b7"}, - {file = "pytest-8.1.1.tar.gz", hash = "sha256:ac978141a75948948817d360297b7aae0fcb9d6ff6bc9ec6d514b85d5a65c044"}, + {file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"}, + {file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"}, ] [package.dependencies] @@ -1426,21 +1464,21 @@ colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=1.4,<2.0" +pluggy = ">=1.5,<2" tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.23.6" +version = "0.23.8" description = "Pytest support for asyncio" optional = false python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.23.6.tar.gz", hash = "sha256:ffe523a89c1c222598c76856e76852b787504ddb72dd5d9b6617ffa8aa2cde5f"}, - {file = "pytest_asyncio-0.23.6-py3-none-any.whl", hash = "sha256:68516fdd1018ac57b846c9846b954f0393b26f094764a28c955eabb0536a4e8a"}, + {file = "pytest_asyncio-0.23.8-py3-none-any.whl", hash = "sha256:50265d892689a5faefb84df80819d1ecef566eb3549cf915dfb33569359d1ce2"}, + {file = "pytest_asyncio-0.23.8.tar.gz", hash = "sha256:759b10b33a6dc61cce40a8bd5205e302978bbbcc00e279a8b61d9a6a3c82e4d3"}, ] [package.dependencies] @@ -1532,17 +1570,17 @@ unidecode = ["Unidecode (>=1.1.1)"] [[package]] name = "python-telegram-bot" -version = "21.7" +version = "21.9" description = "We have made you a wrapper you can't refuse" optional = false python-versions = ">=3.9" files = [ - {file = "python_telegram_bot-21.7-py3-none-any.whl", hash = "sha256:aff1d7245f1b0d4d12d41c9acff74e86d7100713c2204cd02ff17f8d80d18846"}, - {file = "python_telegram_bot-21.7.tar.gz", hash = "sha256:bc8537b77ae02531fc2ad440caafc023fd13f13cf19e592dfa1a9ff84988a012"}, + {file = "python_telegram_bot-21.9-py3-none-any.whl", hash = "sha256:6a5e71056fbd138c78dbdefa3c7834d77022622997c60003c9b442061ee91633"}, + {file = "python_telegram_bot-21.9.tar.gz", hash = "sha256:82588faca44069492b2aea7f3a5d6212e68884f296b9ccd444658d89170f158d"}, ] [package.dependencies] -aiolimiter = {version = ">=1.1.0,<1.2.0", optional = true, markers = "extra == \"all\""} +aiolimiter = {version = ">=1.1,<1.3", optional = true, markers = "extra == \"all\""} apscheduler = {version = ">=3.10.4,<3.11.0", optional = true, markers = "extra == \"all\""} cachetools = {version = ">=5.3.3,<5.6.0", optional = true, markers = "extra == \"all\""} cffi = {version = ">=1.17.0rc1", optional = true, markers = "python_version > \"3.12\" and extra == \"all\""} @@ -1556,13 +1594,13 @@ pytz = {version = ">=2018.6", optional = true, markers = "extra == \"all\""} tornado = {version = ">=6.4,<7.0", optional = true, markers = "extra == \"all\""} [package.extras] -all = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +all = ["aiolimiter (>=1.1,<1.3)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)", "httpx[http2]", "httpx[socks]", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] callback-data = ["cachetools (>=5.3.3,<5.6.0)"] -ext = ["aiolimiter (>=1.1.0,<1.2.0)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] +ext = ["aiolimiter (>=1.1,<1.3)", "apscheduler (>=3.10.4,<3.11.0)", "cachetools (>=5.3.3,<5.6.0)", "pytz (>=2018.6)", "tornado (>=6.4,<7.0)"] http2 = ["httpx[http2]"] job-queue = ["apscheduler (>=3.10.4,<3.11.0)", "pytz (>=2018.6)"] passport = ["cffi (>=1.17.0rc1)", "cryptography (>=39.0.1)"] -rate-limiter = ["aiolimiter (>=1.1.0,<1.2.0)"] +rate-limiter = ["aiolimiter (>=1.1,<1.3)"] socks = ["httpx[socks]"] webhooks = ["tornado (>=6.4,<7.0)"] @@ -1579,73 +1617,75 @@ files = [ [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" 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"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] name = "requests" -version = "2.31.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -1660,31 +1700,32 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "rich" -version = "13.7.1" +version = "13.9.4" description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8.0" files = [ - {file = "rich-13.7.1-py3-none-any.whl", hash = "sha256:4edbae314f59eb482f54e9e30bf00d33350aaa94f4bfcd4e9e3110e64d0d7222"}, - {file = "rich-13.7.1.tar.gz", hash = "sha256:9be308cb1fe2f1f57d67ce99e95af38a1e2bc71ad9813b0e247cf7ffbcc3a432"}, + {file = "rich-13.9.4-py3-none-any.whl", hash = "sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90"}, + {file = "rich-13.9.4.tar.gz", hash = "sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098"}, ] [package.dependencies] markdown-it-py = ">=2.2.0" pygments = ">=2.13.0,<3.0.0" +typing-extensions = {version = ">=4.0.0,<5.0", markers = "python_version < \"3.11\""} [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -1733,101 +1774,105 @@ files = [ [[package]] name = "sphinx" -version = "7.1.2" +version = "7.4.7" description = "Python documentation generator" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinx-7.1.2-py3-none-any.whl", hash = "sha256:d170a81825b2fcacb6dfd5a0d7f578a053e45d3f2b153fecc948c37344eb4cbe"}, - {file = "sphinx-7.1.2.tar.gz", hash = "sha256:780f4d32f1d7d1126576e0e5ecc19dc32ab76cd24e950228dcf7b1f6d3d9e22f"}, + {file = "sphinx-7.4.7-py3-none-any.whl", hash = "sha256:c2419e2135d11f1951cd994d6eb18a1835bd8fdd8429f9ca375dc1f3281bd239"}, + {file = "sphinx-7.4.7.tar.gz", hash = "sha256:242f92a7ea7e6c5b406fdc2615413890ba9f699114a9c09192d7dfead2ee9cfe"}, ] [package.dependencies] -alabaster = ">=0.7,<0.8" -babel = ">=2.9" -colorama = {version = ">=0.4.5", markers = "sys_platform == \"win32\""} -docutils = ">=0.18.1,<0.21" +alabaster = ">=0.7.14,<0.8.0" +babel = ">=2.13" +colorama = {version = ">=0.4.6", markers = "sys_platform == \"win32\""} +docutils = ">=0.20,<0.22" imagesize = ">=1.3" -importlib-metadata = {version = ">=4.8", markers = "python_version < \"3.10\""} -Jinja2 = ">=3.0" -packaging = ">=21.0" -Pygments = ">=2.13" -requests = ">=2.25.0" -snowballstemmer = ">=2.0" +importlib-metadata = {version = ">=6.0", markers = "python_version < \"3.10\""} +Jinja2 = ">=3.1" +packaging = ">=23.0" +Pygments = ">=2.17" +requests = ">=2.30.0" +snowballstemmer = ">=2.2" sphinxcontrib-applehelp = "*" sphinxcontrib-devhelp = "*" sphinxcontrib-htmlhelp = ">=2.0.0" sphinxcontrib-jsmath = "*" sphinxcontrib-qthelp = "*" -sphinxcontrib-serializinghtml = ">=1.1.5" +sphinxcontrib-serializinghtml = ">=1.1.9" +tomli = {version = ">=2", markers = "python_version < \"3.11\""} [package.extras] docs = ["sphinxcontrib-websupport"] -lint = ["docutils-stubs", "flake8 (>=3.5.0)", "flake8-simplify", "isort", "mypy (>=0.990)", "ruff", "sphinx-lint", "types-requests"] -test = ["cython", "filelock", "html5lib", "pytest (>=4.6)"] +lint = ["flake8 (>=6.0)", "importlib-metadata (>=6.0)", "mypy (==1.10.1)", "pytest (>=6.0)", "ruff (==0.5.2)", "sphinx-lint (>=0.9)", "tomli (>=2)", "types-docutils (==0.21.0.20240711)", "types-requests (>=2.30.0)"] +test = ["cython (>=3.0)", "defusedxml (>=0.7.1)", "pytest (>=8.0)", "setuptools (>=70.0)", "typing_extensions (>=4.9)"] [[package]] name = "sphinx-rtd-theme" -version = "2.0.0" +version = "3.0.2" description = "Read the Docs theme for Sphinx" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "sphinx_rtd_theme-2.0.0-py2.py3-none-any.whl", hash = "sha256:ec93d0856dc280cf3aee9a4c9807c60e027c7f7b461b77aeffed682e68f0e586"}, - {file = "sphinx_rtd_theme-2.0.0.tar.gz", hash = "sha256:bd5d7b80622406762073a04ef8fadc5f9151261563d47027de09910ce03afe6b"}, + {file = "sphinx_rtd_theme-3.0.2-py2.py3-none-any.whl", hash = "sha256:422ccc750c3a3a311de4ae327e82affdaf59eb695ba4936538552f3b00f4ee13"}, + {file = "sphinx_rtd_theme-3.0.2.tar.gz", hash = "sha256:b7457bc25dda723b20b086a670b9953c859eab60a2a03ee8eb2bb23e176e5f85"}, ] [package.dependencies] -docutils = "<0.21" -sphinx = ">=5,<8" +docutils = ">0.18,<0.22" +sphinx = ">=6,<9" sphinxcontrib-jquery = ">=4,<5" [package.extras] -dev = ["bump2version", "sphinxcontrib-httpdomain", "transifex-client", "wheel"] +dev = ["bump2version", "transifex-client", "twine", "wheel"] [[package]] name = "sphinxcontrib-applehelp" -version = "1.0.4" +version = "2.0.0" description = "sphinxcontrib-applehelp is a Sphinx extension which outputs Apple help books" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-applehelp-1.0.4.tar.gz", hash = "sha256:828f867945bbe39817c210a1abfd1bc4895c8b73fcaade56d45357a348a07d7e"}, - {file = "sphinxcontrib_applehelp-1.0.4-py3-none-any.whl", hash = "sha256:29d341f67fb0f6f586b23ad80e072c8e6ad0b48417db2bde114a4c9746feb228"}, + {file = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl", hash = "sha256:4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5"}, + {file = "sphinxcontrib_applehelp-2.0.0.tar.gz", hash = "sha256:2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-devhelp" -version = "1.0.2" -description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp document." +version = "2.0.0" +description = "sphinxcontrib-devhelp is a sphinx extension which outputs Devhelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-devhelp-1.0.2.tar.gz", hash = "sha256:ff7f1afa7b9642e7060379360a67e9c41e8f3121f2ce9164266f61b9f4b338e4"}, - {file = "sphinxcontrib_devhelp-1.0.2-py2.py3-none-any.whl", hash = "sha256:8165223f9a335cc1af7ffe1ed31d2871f325254c0423bc0c4c7cd1c1e4734a2e"}, + {file = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl", hash = "sha256:aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2"}, + {file = "sphinxcontrib_devhelp-2.0.0.tar.gz", hash = "sha256:411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] name = "sphinxcontrib-htmlhelp" -version = "2.0.1" +version = "2.1.0" description = "sphinxcontrib-htmlhelp is a sphinx extension which renders HTML help files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-htmlhelp-2.0.1.tar.gz", hash = "sha256:0cbdd302815330058422b98a113195c9249825d681e18f11e8b1f78a2f11efff"}, - {file = "sphinxcontrib_htmlhelp-2.0.1-py3-none-any.whl", hash = "sha256:c38cb46dccf316c79de6e5515e1770414b797162b23cd3d06e67020e1d2a6903"}, + {file = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl", hash = "sha256:166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8"}, + {file = "sphinxcontrib_htmlhelp-2.1.0.tar.gz", hash = "sha256:c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["html5lib", "pytest"] [[package]] @@ -1860,32 +1905,34 @@ test = ["flake8", "mypy", "pytest"] [[package]] name = "sphinxcontrib-qthelp" -version = "1.0.3" -description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp document." +version = "2.0.0" +description = "sphinxcontrib-qthelp is a sphinx extension which outputs QtHelp documents" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-qthelp-1.0.3.tar.gz", hash = "sha256:4c33767ee058b70dba89a6fc5c1892c0d57a54be67ddd3e7875a18d14cba5a72"}, - {file = "sphinxcontrib_qthelp-1.0.3-py2.py3-none-any.whl", hash = "sha256:bd9fc24bcb748a8d51fd4ecaade681350aa63009a347a8c14e637895444dfab6"}, + {file = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl", hash = "sha256:b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb"}, + {file = "sphinxcontrib_qthelp-2.0.0.tar.gz", hash = "sha256:4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] -test = ["pytest"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] +test = ["defusedxml (>=0.7.1)", "pytest"] [[package]] name = "sphinxcontrib-serializinghtml" -version = "1.1.5" -description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)." +version = "2.0.0" +description = "sphinxcontrib-serializinghtml is a sphinx extension which outputs \"serialized\" HTML files (json and pickle)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.9" files = [ - {file = "sphinxcontrib-serializinghtml-1.1.5.tar.gz", hash = "sha256:aa5f6de5dfdf809ef505c4895e51ef5c9eac17d0f287933eb49ec495280b6952"}, - {file = "sphinxcontrib_serializinghtml-1.1.5-py2.py3-none-any.whl", hash = "sha256:352a9a00ae864471d3a7ead8d7d79f5fc0b57e8b3f95e9867eb9eb28999b92fd"}, + {file = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl", hash = "sha256:6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331"}, + {file = "sphinxcontrib_serializinghtml-2.0.0.tar.gz", hash = "sha256:e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d"}, ] [package.extras] -lint = ["docutils-stubs", "flake8", "mypy"] +lint = ["mypy", "ruff (==0.5.5)", "types-docutils"] +standalone = ["Sphinx (>=5)"] test = ["pytest"] [[package]] @@ -1919,24 +1966,54 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"}, + {file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"}, + {file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"}, + {file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"}, + {file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"}, + {file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"}, + {file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"}, + {file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"}, + {file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"}, + {file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"}, + {file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"}, + {file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"}, + {file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"}, + {file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"}, + {file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"}, + {file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"}, + {file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"}, + {file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"}, ] [[package]] name = "tomlkit" -version = "0.12.5" +version = "0.13.2" description = "Style preserving TOML library" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "tomlkit-0.12.5-py3-none-any.whl", hash = "sha256:af914f5a9c59ed9d0762c7b64d3b5d5df007448eb9cd2edc8a46b1eafead172f"}, - {file = "tomlkit-0.12.5.tar.gz", hash = "sha256:eef34fba39834d4d6b73c9ba7f3e4d1c417a4e56f89a7e96e090dd0d24b8fb3c"}, + {file = "tomlkit-0.13.2-py3-none-any.whl", hash = "sha256:7a974427f6e119197f670fbbbeae7bef749a6c14e793db934baefc1b5f03efde"}, + {file = "tomlkit-0.13.2.tar.gz", hash = "sha256:fff5fe59a87295b278abd31bec92c15d9bc4a06885ab12bcea52c71119392e79"}, ] [[package]] @@ -1982,24 +2059,24 @@ test = ["black (>=22.3.0,<23.0.0)", "coverage (>=6.2,<7.0)", "isort (>=5.0.6,<6. [[package]] name = "types-python-dateutil" -version = "2.9.0.20240316" +version = "2.9.0.20241206" description = "Typing stubs for python-dateutil" optional = false python-versions = ">=3.8" files = [ - {file = "types-python-dateutil-2.9.0.20240316.tar.gz", hash = "sha256:5d2f2e240b86905e40944dd787db6da9263f0deabef1076ddaed797351ec0202"}, - {file = "types_python_dateutil-2.9.0.20240316-py3-none-any.whl", hash = "sha256:6b8cb66d960771ce5ff974e9dd45e38facb81718cc1e208b10b1baccbfdbee3b"}, + {file = "types_python_dateutil-2.9.0.20241206-py3-none-any.whl", hash = "sha256:e248a4bc70a486d3e3ec84d0dc30eec3a5f979d6e7ee4123ae043eedbb987f53"}, + {file = "types_python_dateutil-2.9.0.20241206.tar.gz", hash = "sha256:18f493414c26ffba692a72369fea7a154c502646301ebfe3d56a04b3767284cb"}, ] [[package]] name = "typing-extensions" -version = "4.11.0" +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.11.0-py3-none-any.whl", hash = "sha256:c1f94d72897edaf4ce775bb7558d5b79d8126906a14ea5ed1635921406c0387a"}, - {file = "typing_extensions-4.11.0.tar.gz", hash = "sha256:83f085bd5ca59c80295fc2a82ab5dac679cbe02b9f33f7d83af68e241bea51b0"}, + {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]] @@ -2032,13 +2109,13 @@ devenv = ["check-manifest", "pytest (>=4.3)", "pytest-cov", "pytest-mock (>=3.3) [[package]] name = "urllib3" -version = "2.2.1" +version = "2.2.3" 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.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] @@ -2075,130 +2152,133 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)", [[package]] name = "uvloop" -version = "0.19.0" +version = "0.21.0" description = "Fast implementation of asyncio event loop on top of libuv" optional = false python-versions = ">=3.8.0" files = [ - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:de4313d7f575474c8f5a12e163f6d89c0a878bc49219641d49e6f1444369a90e"}, - {file = "uvloop-0.19.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5588bd21cf1fcf06bded085f37e43ce0e00424197e7c10e77afd4bbefffef428"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b1fd71c3843327f3bbc3237bedcdb6504fd50368ab3e04d0410e52ec293f5b8"}, - {file = "uvloop-0.19.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a05128d315e2912791de6088c34136bfcdd0c7cbc1cf85fd6fd1bb321b7c849"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:cd81bdc2b8219cb4b2556eea39d2e36bfa375a2dd021404f90a62e44efaaf957"}, - {file = "uvloop-0.19.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:5f17766fb6da94135526273080f3455a112f82570b2ee5daa64d682387fe0dcd"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4ce6b0af8f2729a02a5d1575feacb2a94fc7b2e983868b009d51c9a9d2149bef"}, - {file = "uvloop-0.19.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:31e672bb38b45abc4f26e273be83b72a0d28d074d5b370fc4dcf4c4eb15417d2"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:570fc0ed613883d8d30ee40397b79207eedd2624891692471808a95069a007c1"}, - {file = "uvloop-0.19.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5138821e40b0c3e6c9478643b4660bd44372ae1e16a322b8fc07478f92684e24"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:91ab01c6cd00e39cde50173ba4ec68a1e578fee9279ba64f5221810a9e786533"}, - {file = "uvloop-0.19.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:47bf3e9312f63684efe283f7342afb414eea4d3011542155c7e625cd799c3b12"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:da8435a3bd498419ee8c13c34b89b5005130a476bda1d6ca8cfdde3de35cd650"}, - {file = "uvloop-0.19.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:02506dc23a5d90e04d4f65c7791e65cf44bd91b37f24cfc3ef6cf2aff05dc7ec"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693049be9d36fef81741fddb3f441673ba12a34a704e7b4361efb75cf30befc"}, - {file = "uvloop-0.19.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7010271303961c6f0fe37731004335401eb9075a12680738731e9c92ddd96ad6"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:5daa304d2161d2918fa9a17d5635099a2f78ae5b5960e742b2fcfbb7aefaa593"}, - {file = "uvloop-0.19.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7207272c9520203fea9b93843bb775d03e1cf88a80a936ce760f60bb5add92f3"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:78ab247f0b5671cc887c31d33f9b3abfb88d2614b84e4303f1a63b46c046c8bd"}, - {file = "uvloop-0.19.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:472d61143059c84947aa8bb74eabbace30d577a03a1805b77933d6bd13ddebbd"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45bf4c24c19fb8a50902ae37c5de50da81de4922af65baf760f7c0c42e1088be"}, - {file = "uvloop-0.19.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271718e26b3e17906b28b67314c45d19106112067205119dddbd834c2b7ce797"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:34175c9fd2a4bc3adc1380e1261f60306344e3407c20a4d684fd5f3be010fa3d"}, - {file = "uvloop-0.19.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e27f100e1ff17f6feeb1f33968bc185bf8ce41ca557deee9d9bbbffeb72030b7"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:13dfdf492af0aa0a0edf66807d2b465607d11c4fa48f4a1fd41cbea5b18e8e8b"}, - {file = "uvloop-0.19.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6e3d4e85ac060e2342ff85e90d0c04157acb210b9ce508e784a944f852a40e67"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8ca4956c9ab567d87d59d49fa3704cf29e37109ad348f2d5223c9bf761a332e7"}, - {file = "uvloop-0.19.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f467a5fd23b4fc43ed86342641f3936a68ded707f4627622fa3f82a120e18256"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:492e2c32c2af3f971473bc22f086513cedfc66a130756145a931a90c3958cb17"}, - {file = "uvloop-0.19.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:2df95fca285a9f5bfe730e51945ffe2fa71ccbfdde3b0da5772b4ee4f2e770d5"}, - {file = "uvloop-0.19.0.tar.gz", hash = "sha256:0246f4fd1bf2bf702e06b0d45ee91677ee5c31242f39aab4ea6fe0c51aedd0fd"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f"}, + {file = "uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26"}, + {file = "uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f"}, + {file = "uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8"}, + {file = "uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e"}, + {file = "uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6"}, + {file = "uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c"}, + {file = "uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d"}, + {file = "uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb"}, + {file = "uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281"}, + {file = "uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6"}, + {file = "uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc"}, + {file = "uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:17df489689befc72c39a08359efac29bbee8eee5209650d4b9f34df73d22e414"}, + {file = "uvloop-0.21.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:bc09f0ff191e61c2d592a752423c767b4ebb2986daa9ed62908e2b1b9a9ae206"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f0ce1b49560b1d2d8a2977e3ba4afb2414fb46b86a1b64056bc4ab929efdafbe"}, + {file = "uvloop-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e678ad6fe52af2c58d2ae3c73dc85524ba8abe637f134bf3564ed07f555c5e79"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:460def4412e473896ef179a1671b40c039c7012184b627898eea5072ef6f017a"}, + {file = "uvloop-0.21.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:10da8046cc4a8f12c91a1c39d1dd1585c41162a15caaef165c2174db9ef18bdc"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c097078b8031190c934ed0ebfee8cc5f9ba9642e6eb88322b9958b649750f72b"}, + {file = "uvloop-0.21.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:46923b0b5ee7fc0020bef24afe7836cb068f5050ca04caf6b487c513dc1a20b2"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:53e420a3afe22cdcf2a0f4846e377d16e718bc70103d7088a4f7623567ba5fb0"}, + {file = "uvloop-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88cb67cdbc0e483da00af0b2c3cdad4b7c61ceb1ee0f33fe00e09c81e3a6cb75"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:221f4f2a1f46032b403bf3be628011caf75428ee3cc204a22addf96f586b19fd"}, + {file = "uvloop-0.21.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2d1f581393673ce119355d56da84fe1dd9d2bb8b3d13ce792524e1607139feff"}, + {file = "uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3"}, ] [package.extras] +dev = ["Cython (>=3.0,<4.0)", "setuptools (>=60)"] docs = ["Sphinx (>=4.1.2,<4.2.0)", "sphinx-rtd-theme (>=0.5.2,<0.6.0)", "sphinxcontrib-asyncio (>=0.3.0,<0.4.0)"] -test = ["Cython (>=0.29.36,<0.30.0)", "aiohttp (==3.9.0b0)", "aiohttp (>=3.8.1)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] +test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", "pyOpenSSL (>=23.0.0,<23.1.0)", "pycodestyle (>=2.9.0,<2.10.0)"] [[package]] name = "watchfiles" -version = "0.21.0" +version = "1.0.3" description = "Simple, modern and high performance file watching and code reload in python." optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "watchfiles-0.21.0-cp310-cp310-macosx_10_7_x86_64.whl", hash = "sha256:27b4035013f1ea49c6c0b42d983133b136637a527e48c132d368eb19bf1ac6aa"}, - {file = "watchfiles-0.21.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c81818595eff6e92535ff32825f31c116f867f64ff8cdf6562cd1d6b2e1e8f3e"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:6c107ea3cf2bd07199d66f156e3ea756d1b84dfd43b542b2d870b77868c98c03"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d9ac347653ebd95839a7c607608703b20bc07e577e870d824fa4801bc1cb124"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5eb86c6acb498208e7663ca22dbe68ca2cf42ab5bf1c776670a50919a56e64ab"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f564bf68404144ea6b87a78a3f910cc8de216c6b12a4cf0b27718bf4ec38d303"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d0f32ebfaa9c6011f8454994f86108c2eb9c79b8b7de00b36d558cadcedaa3d"}, - {file = "watchfiles-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b6d45d9b699ecbac6c7bd8e0a2609767491540403610962968d258fd6405c17c"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:aff06b2cac3ef4616e26ba17a9c250c1fe9dd8a5d907d0193f84c499b1b6e6a9"}, - {file = "watchfiles-0.21.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d9792dff410f266051025ecfaa927078b94cc7478954b06796a9756ccc7e14a9"}, - {file = "watchfiles-0.21.0-cp310-none-win32.whl", hash = "sha256:214cee7f9e09150d4fb42e24919a1e74d8c9b8a9306ed1474ecaddcd5479c293"}, - {file = "watchfiles-0.21.0-cp310-none-win_amd64.whl", hash = "sha256:1ad7247d79f9f55bb25ab1778fd47f32d70cf36053941f07de0b7c4e96b5d235"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_10_7_x86_64.whl", hash = "sha256:668c265d90de8ae914f860d3eeb164534ba2e836811f91fecc7050416ee70aa7"}, - {file = "watchfiles-0.21.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a23092a992e61c3a6a70f350a56db7197242f3490da9c87b500f389b2d01eef"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:e7941bbcfdded9c26b0bf720cb7e6fd803d95a55d2c14b4bd1f6a2772230c586"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:11cd0c3100e2233e9c53106265da31d574355c288e15259c0d40a4405cbae317"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d78f30cbe8b2ce770160d3c08cff01b2ae9306fe66ce899b73f0409dc1846c1b"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6674b00b9756b0af620aa2a3346b01f8e2a3dc729d25617e1b89cf6af4a54eb1"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fd7ac678b92b29ba630d8c842d8ad6c555abda1b9ef044d6cc092dacbfc9719d"}, - {file = "watchfiles-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c873345680c1b87f1e09e0eaf8cf6c891b9851d8b4d3645e7efe2ec20a20cc7"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49f56e6ecc2503e7dbe233fa328b2be1a7797d31548e7a193237dcdf1ad0eee0"}, - {file = "watchfiles-0.21.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:02d91cbac553a3ad141db016e3350b03184deaafeba09b9d6439826ee594b365"}, - {file = "watchfiles-0.21.0-cp311-none-win32.whl", hash = "sha256:ebe684d7d26239e23d102a2bad2a358dedf18e462e8808778703427d1f584400"}, - {file = "watchfiles-0.21.0-cp311-none-win_amd64.whl", hash = "sha256:4566006aa44cb0d21b8ab53baf4b9c667a0ed23efe4aaad8c227bfba0bf15cbe"}, - {file = "watchfiles-0.21.0-cp311-none-win_arm64.whl", hash = "sha256:c550a56bf209a3d987d5a975cdf2063b3389a5d16caf29db4bdddeae49f22078"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_10_7_x86_64.whl", hash = "sha256:51ddac60b96a42c15d24fbdc7a4bfcd02b5a29c047b7f8bf63d3f6f5a860949a"}, - {file = "watchfiles-0.21.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:511f0b034120cd1989932bf1e9081aa9fb00f1f949fbd2d9cab6264916ae89b1"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cfb92d49dbb95ec7a07511bc9efb0faff8fe24ef3805662b8d6808ba8409a71a"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f92944efc564867bbf841c823c8b71bb0be75e06b8ce45c084b46411475a915"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:642d66b75eda909fd1112d35c53816d59789a4b38c141a96d62f50a3ef9b3360"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d23bcd6c8eaa6324fe109d8cac01b41fe9a54b8c498af9ce464c1aeeb99903d6"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18d5b4da8cf3e41895b34e8c37d13c9ed294954907929aacd95153508d5d89d7"}, - {file = "watchfiles-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1b8d1eae0f65441963d805f766c7e9cd092f91e0c600c820c764a4ff71a0764c"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1fd9a5205139f3c6bb60d11f6072e0552f0a20b712c85f43d42342d162be1235"}, - {file = "watchfiles-0.21.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a1e3014a625bcf107fbf38eece0e47fa0190e52e45dc6eee5a8265ddc6dc5ea7"}, - {file = "watchfiles-0.21.0-cp312-none-win32.whl", hash = "sha256:9d09869f2c5a6f2d9df50ce3064b3391d3ecb6dced708ad64467b9e4f2c9bef3"}, - {file = "watchfiles-0.21.0-cp312-none-win_amd64.whl", hash = "sha256:18722b50783b5e30a18a8a5db3006bab146d2b705c92eb9a94f78c72beb94094"}, - {file = "watchfiles-0.21.0-cp312-none-win_arm64.whl", hash = "sha256:a3b9bec9579a15fb3ca2d9878deae789df72f2b0fdaf90ad49ee389cad5edab6"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_10_7_x86_64.whl", hash = "sha256:4ea10a29aa5de67de02256a28d1bf53d21322295cb00bd2d57fcd19b850ebd99"}, - {file = "watchfiles-0.21.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:40bca549fdc929b470dd1dbfcb47b3295cb46a6d2c90e50588b0a1b3bd98f429"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9b37a7ba223b2f26122c148bb8d09a9ff312afca998c48c725ff5a0a632145f7"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec8c8900dc5c83650a63dd48c4d1d245343f904c4b64b48798c67a3767d7e165"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8ad3fe0a3567c2f0f629d800409cd528cb6251da12e81a1f765e5c5345fd0137"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9d353c4cfda586db2a176ce42c88f2fc31ec25e50212650c89fdd0f560ee507b"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83a696da8922314ff2aec02987eefb03784f473281d740bf9170181829133765"}, - {file = "watchfiles-0.21.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5a03651352fc20975ee2a707cd2d74a386cd303cc688f407296064ad1e6d1562"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:3ad692bc7792be8c32918c699638b660c0de078a6cbe464c46e1340dadb94c19"}, - {file = "watchfiles-0.21.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06247538e8253975bdb328e7683f8515ff5ff041f43be6c40bff62d989b7d0b0"}, - {file = "watchfiles-0.21.0-cp38-none-win32.whl", hash = "sha256:9a0aa47f94ea9a0b39dd30850b0adf2e1cd32a8b4f9c7aa443d852aacf9ca214"}, - {file = "watchfiles-0.21.0-cp38-none-win_amd64.whl", hash = "sha256:8d5f400326840934e3507701f9f7269247f7c026d1b6cfd49477d2be0933cfca"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_10_7_x86_64.whl", hash = "sha256:7f762a1a85a12cc3484f77eee7be87b10f8c50b0b787bb02f4e357403cad0c0e"}, - {file = "watchfiles-0.21.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6e9be3ef84e2bb9710f3f777accce25556f4a71e15d2b73223788d528fcc2052"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4c48a10d17571d1275701e14a601e36959ffada3add8cdbc9e5061a6e3579a5d"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c889025f59884423428c261f212e04d438de865beda0b1e1babab85ef4c0f01"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:66fac0c238ab9a2e72d026b5fb91cb902c146202bbd29a9a1a44e8db7b710b6f"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b4a21f71885aa2744719459951819e7bf5a906a6448a6b2bbce8e9cc9f2c8128"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c9198c989f47898b2c22201756f73249de3748e0fc9de44adaf54a8b259cc0c"}, - {file = "watchfiles-0.21.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8f57c4461cd24fda22493109c45b3980863c58a25b8bec885ca8bea6b8d4b28"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:853853cbf7bf9408b404754b92512ebe3e3a83587503d766d23e6bf83d092ee6"}, - {file = "watchfiles-0.21.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d5b1dc0e708fad9f92c296ab2f948af403bf201db8fb2eb4c8179db143732e49"}, - {file = "watchfiles-0.21.0-cp39-none-win32.whl", hash = "sha256:59137c0c6826bd56c710d1d2bda81553b5e6b7c84d5a676747d80caf0409ad94"}, - {file = "watchfiles-0.21.0-cp39-none-win_amd64.whl", hash = "sha256:6cb8fdc044909e2078c248986f2fc76f911f72b51ea4a4fbbf472e01d14faa58"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_10_7_x86_64.whl", hash = "sha256:ab03a90b305d2588e8352168e8c5a1520b721d2d367f31e9332c4235b30b8994"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:927c589500f9f41e370b0125c12ac9e7d3a2fd166b89e9ee2828b3dda20bfe6f"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1bd467213195e76f838caf2c28cd65e58302d0254e636e7c0fca81efa4a2e62c"}, - {file = "watchfiles-0.21.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:02b73130687bc3f6bb79d8a170959042eb56eb3a42df3671c79b428cd73f17cc"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_10_7_x86_64.whl", hash = "sha256:08dca260e85ffae975448e344834d765983237ad6dc308231aa16e7933db763e"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:3ccceb50c611c433145502735e0370877cced72a6c70fd2410238bcbc7fe51d8"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:57d430f5fb63fea141ab71ca9c064e80de3a20b427ca2febcbfcef70ff0ce895"}, - {file = "watchfiles-0.21.0-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dd5fad9b9c0dd89904bbdea978ce89a2b692a7ee8a0ce19b940e538c88a809c"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_10_7_x86_64.whl", hash = "sha256:be6dd5d52b73018b21adc1c5d28ac0c68184a64769052dfeb0c5d9998e7f56a2"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:b3cab0e06143768499384a8a5efb9c4dc53e19382952859e4802f294214f36ec"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c6ed10c2497e5fedadf61e465b3ca12a19f96004c15dcffe4bd442ebadc2d85"}, - {file = "watchfiles-0.21.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:43babacef21c519bc6631c5fce2a61eccdfc011b4bcb9047255e9620732c8097"}, - {file = "watchfiles-0.21.0.tar.gz", hash = "sha256:c76c635fabf542bb78524905718c39f736a98e5ab25b23ec6d4abede1a85a6a3"}, + {file = "watchfiles-1.0.3-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:1da46bb1eefb5a37a8fb6fd52ad5d14822d67c498d99bda8754222396164ae42"}, + {file = "watchfiles-1.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2b961b86cd3973f5822826017cad7f5a75795168cb645c3a6b30c349094e02e3"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34e87c7b3464d02af87f1059fedda5484e43b153ef519e4085fe1a03dd94801e"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d9dd2b89a16cf7ab9c1170b5863e68de6bf83db51544875b25a5f05a7269e678"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2b4691234d31686dca133c920f94e478b548a8e7c750f28dbbc2e4333e0d3da9"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:90b0fe1fcea9bd6e3084b44875e179b4adcc4057a3b81402658d0eb58c98edf8"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0b90651b4cf9e158d01faa0833b073e2e37719264bcee3eac49fc3c74e7d304b"}, + {file = "watchfiles-1.0.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c2e9fe695ff151b42ab06501820f40d01310fbd58ba24da8923ace79cf6d702d"}, + {file = "watchfiles-1.0.3-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:62691f1c0894b001c7cde1195c03b7801aaa794a837bd6eef24da87d1542838d"}, + {file = "watchfiles-1.0.3-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:275c1b0e942d335fccb6014d79267d1b9fa45b5ac0639c297f1e856f2f532552"}, + {file = "watchfiles-1.0.3-cp310-cp310-win32.whl", hash = "sha256:06ce08549e49ba69ccc36fc5659a3d0ff4e3a07d542b895b8a9013fcab46c2dc"}, + {file = "watchfiles-1.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:f280b02827adc9d87f764972fbeb701cf5611f80b619c20568e1982a277d6146"}, + {file = "watchfiles-1.0.3-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:ffe709b1d0bc2e9921257569675674cafb3a5f8af689ab9f3f2b3f88775b960f"}, + {file = "watchfiles-1.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:418c5ce332f74939ff60691e5293e27c206c8164ce2b8ce0d9abf013003fb7fe"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f492d2907263d6d0d52f897a68647195bc093dafed14508a8d6817973586b6b"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:48c9f3bc90c556a854f4cab6a79c16974099ccfa3e3e150673d82d47a4bc92c9"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:75d3bcfa90454dba8df12adc86b13b6d85fda97d90e708efc036c2760cc6ba44"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5691340f259b8f76b45fb31b98e594d46c36d1dc8285efa7975f7f50230c9093"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e263cc718545b7f897baeac1f00299ab6fabe3e18caaacacb0edf6d5f35513c"}, + {file = "watchfiles-1.0.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c6cf7709ed3e55704cc06f6e835bf43c03bc8e3cb8ff946bf69a2e0a78d9d77"}, + {file = "watchfiles-1.0.3-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:703aa5e50e465be901e0e0f9d5739add15e696d8c26c53bc6fc00eb65d7b9469"}, + {file = "watchfiles-1.0.3-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:bfcae6aecd9e0cb425f5145afee871465b98b75862e038d42fe91fd753ddd780"}, + {file = "watchfiles-1.0.3-cp311-cp311-win32.whl", hash = "sha256:6a76494d2c5311584f22416c5a87c1e2cb954ff9b5f0988027bc4ef2a8a67181"}, + {file = "watchfiles-1.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:cf745cbfad6389c0e331786e5fe9ae3f06e9d9c2ce2432378e1267954793975c"}, + {file = "watchfiles-1.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:2dcc3f60c445f8ce14156854a072ceb36b83807ed803d37fdea2a50e898635d6"}, + {file = "watchfiles-1.0.3-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:93436ed550e429da007fbafb723e0769f25bae178fbb287a94cb4ccdf42d3af3"}, + {file = "watchfiles-1.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:c18f3502ad0737813c7dad70e3e1cc966cc147fbaeef47a09463bbffe70b0a00"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a5bc3ca468bb58a2ef50441f953e1f77b9a61bd1b8c347c8223403dc9b4ac9a"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0d1ec043f02ca04bf21b1b32cab155ce90c651aaf5540db8eb8ad7f7e645cba8"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f58d3bfafecf3d81c15d99fc0ecf4319e80ac712c77cf0ce2661c8cf8bf84066"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1df924ba82ae9e77340101c28d56cbaff2c991bd6fe8444a545d24075abb0a87"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:632a52dcaee44792d0965c17bdfe5dc0edad5b86d6a29e53d6ad4bf92dc0ff49"}, + {file = "watchfiles-1.0.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bf4b459d94a0387617a1b499f314aa04d8a64b7a0747d15d425b8c8b151da0"}, + {file = "watchfiles-1.0.3-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:ca94c85911601b097d53caeeec30201736ad69a93f30d15672b967558df02885"}, + {file = "watchfiles-1.0.3-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65ab1fb635476f6170b07e8e21db0424de94877e4b76b7feabfe11f9a5fc12b5"}, + {file = "watchfiles-1.0.3-cp312-cp312-win32.whl", hash = "sha256:49bc1bc26abf4f32e132652f4b3bfeec77d8f8f62f57652703ef127e85a3e38d"}, + {file = "watchfiles-1.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:48681c86f2cb08348631fed788a116c89c787fdf1e6381c5febafd782f6c3b44"}, + {file = "watchfiles-1.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:9e080cf917b35b20c889225a13f290f2716748362f6071b859b60b8847a6aa43"}, + {file = "watchfiles-1.0.3-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:e153a690b7255c5ced17895394b4f109d5dcc2a4f35cb809374da50f0e5c456a"}, + {file = "watchfiles-1.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ac1be85fe43b4bf9a251978ce5c3bb30e1ada9784290441f5423a28633a958a7"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2ec98e31e1844eac860e70d9247db9d75440fc8f5f679c37d01914568d18721"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0179252846be03fa97d4d5f8233d1c620ef004855f0717712ae1c558f1974a16"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:995c374e86fa82126c03c5b4630c4e312327ecfe27761accb25b5e1d7ab50ec8"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:29b9cb35b7f290db1c31fb2fdf8fc6d3730cfa4bca4b49761083307f441cac5a"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f8dc09ae69af50bead60783180f656ad96bd33ffbf6e7a6fce900f6d53b08f1"}, + {file = "watchfiles-1.0.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:489b80812f52a8d8c7b0d10f0d956db0efed25df2821c7a934f6143f76938bd6"}, + {file = "watchfiles-1.0.3-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:228e2247de583475d4cebf6b9af5dc9918abb99d1ef5ee737155bb39fb33f3c0"}, + {file = "watchfiles-1.0.3-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:1550be1a5cb3be08a3fb84636eaafa9b7119b70c71b0bed48726fd1d5aa9b868"}, + {file = "watchfiles-1.0.3-cp313-cp313-win32.whl", hash = "sha256:16db2d7e12f94818cbf16d4c8938e4d8aaecee23826344addfaaa671a1527b07"}, + {file = "watchfiles-1.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:160eff7d1267d7b025e983ca8460e8cc67b328284967cbe29c05f3c3163711a3"}, + {file = "watchfiles-1.0.3-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:c05b021f7b5aa333124f2a64d56e4cb9963b6efdf44e8d819152237bbd93ba15"}, + {file = "watchfiles-1.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:310505ad305e30cb6c5f55945858cdbe0eb297fc57378f29bacceb534ac34199"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ddff3f8b9fa24a60527c137c852d0d9a7da2a02cf2151650029fdc97c852c974"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:46e86ed457c3486080a72bc837300dd200e18d08183f12b6ca63475ab64ed651"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f79fe7993e230a12172ce7d7c7db061f046f672f2b946431c81aff8f60b2758b"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ea2b51c5f38bad812da2ec0cd7eec09d25f521a8b6b6843cbccedd9a1d8a5c15"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fe4e740ea94978b2b2ab308cbf9270a246bcbb44401f77cc8740348cbaeac3d"}, + {file = "watchfiles-1.0.3-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9af037d3df7188ae21dc1c7624501f2f90d81be6550904e07869d8d0e6766655"}, + {file = "watchfiles-1.0.3-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:52bb50a4c4ca2a689fdba84ba8ecc6a4e6210f03b6af93181bb61c4ec3abaf86"}, + {file = "watchfiles-1.0.3-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c14a07bdb475eb696f85c715dbd0f037918ccbb5248290448488a0b4ef201aad"}, + {file = "watchfiles-1.0.3-cp39-cp39-win32.whl", hash = "sha256:be37f9b1f8934cd9e7eccfcb5612af9fb728fecbe16248b082b709a9d1b348bf"}, + {file = "watchfiles-1.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:ef9ec8068cf23458dbf36a08e0c16f0a2df04b42a8827619646637be1769300a"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:84fac88278f42d61c519a6c75fb5296fd56710b05bbdcc74bdf85db409a03780"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:c68be72b1666d93b266714f2d4092d78dc53bd11cf91ed5a3c16527587a52e29"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:889a37e2acf43c377b5124166bece139b4c731b61492ab22e64d371cce0e6e80"}, + {file = "watchfiles-1.0.3-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ca05cacf2e5c4a97d02a2878a24020daca21dbb8823b023b978210a75c79098"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:8af4b582d5fc1b8465d1d2483e5e7b880cc1a4e99f6ff65c23d64d070867ac58"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:127de3883bdb29dbd3b21f63126bb8fa6e773b74eaef46521025a9ce390e1073"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:713f67132346bdcb4c12df185c30cf04bdf4bf6ea3acbc3ace0912cab6b7cb8c"}, + {file = "watchfiles-1.0.3-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abd85de513eb83f5ec153a802348e7a5baa4588b818043848247e3e8986094e8"}, + {file = "watchfiles-1.0.3.tar.gz", hash = "sha256:f3ff7da165c99a5412fe5dd2304dd2dbaaaa5da718aad942dcb3a178eaa70c56"}, ] [package.dependencies] @@ -2206,83 +2286,80 @@ anyio = ">=3.0.0" [[package]] name = "websockets" -version = "12.0" +version = "14.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "websockets-12.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d554236b2a2006e0ce16315c16eaa0d628dab009c33b63ea03f41c6107958374"}, - {file = "websockets-12.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2d225bb6886591b1746b17c0573e29804619c8f755b5598d875bb4235ea639be"}, - {file = "websockets-12.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eb809e816916a3b210bed3c82fb88eaf16e8afcf9c115ebb2bacede1797d2547"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c588f6abc13f78a67044c6b1273a99e1cf31038ad51815b3b016ce699f0d75c2"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5aa9348186d79a5f232115ed3fa9020eab66d6c3437d72f9d2c8ac0c6858c558"}, - {file = "websockets-12.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6350b14a40c95ddd53e775dbdbbbc59b124a5c8ecd6fbb09c2e52029f7a9f480"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:70ec754cc2a769bcd218ed8d7209055667b30860ffecb8633a834dde27d6307c"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6e96f5ed1b83a8ddb07909b45bd94833b0710f738115751cdaa9da1fb0cb66e8"}, - {file = "websockets-12.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:4d87be612cbef86f994178d5186add3d94e9f31cc3cb499a0482b866ec477603"}, - {file = "websockets-12.0-cp310-cp310-win32.whl", hash = "sha256:befe90632d66caaf72e8b2ed4d7f02b348913813c8b0a32fae1cc5fe3730902f"}, - {file = "websockets-12.0-cp310-cp310-win_amd64.whl", hash = "sha256:363f57ca8bc8576195d0540c648aa58ac18cf85b76ad5202b9f976918f4219cf"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5d873c7de42dea355d73f170be0f23788cf3fa9f7bed718fd2830eefedce01b4"}, - {file = "websockets-12.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3f61726cae9f65b872502ff3c1496abc93ffbe31b278455c418492016e2afc8f"}, - {file = "websockets-12.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ed2fcf7a07334c77fc8a230755c2209223a7cc44fc27597729b8ef5425aa61a3"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8e332c210b14b57904869ca9f9bf4ca32f5427a03eeb625da9b616c85a3a506c"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5693ef74233122f8ebab026817b1b37fe25c411ecfca084b29bc7d6efc548f45"}, - {file = "websockets-12.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e9e7db18b4539a29cc5ad8c8b252738a30e2b13f033c2d6e9d0549b45841c04"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6e2df67b8014767d0f785baa98393725739287684b9f8d8a1001eb2839031447"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bea88d71630c5900690fcb03161ab18f8f244805c59e2e0dc4ffadae0a7ee0ca"}, - {file = "websockets-12.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:dff6cdf35e31d1315790149fee351f9e52978130cef6c87c4b6c9b3baf78bc53"}, - {file = "websockets-12.0-cp311-cp311-win32.whl", hash = "sha256:3e3aa8c468af01d70332a382350ee95f6986db479ce7af14d5e81ec52aa2b402"}, - {file = "websockets-12.0-cp311-cp311-win_amd64.whl", hash = "sha256:25eb766c8ad27da0f79420b2af4b85d29914ba0edf69f547cc4f06ca6f1d403b"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0e6e2711d5a8e6e482cacb927a49a3d432345dfe7dea8ace7b5790df5932e4df"}, - {file = "websockets-12.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:dbcf72a37f0b3316e993e13ecf32f10c0e1259c28ffd0a85cee26e8549595fbc"}, - {file = "websockets-12.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:12743ab88ab2af1d17dd4acb4645677cb7063ef4db93abffbf164218a5d54c6b"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7b645f491f3c48d3f8a00d1fce07445fab7347fec54a3e65f0725d730d5b99cb"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9893d1aa45a7f8b3bc4510f6ccf8db8c3b62120917af15e3de247f0780294b92"}, - {file = "websockets-12.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f38a7b376117ef7aff996e737583172bdf535932c9ca021746573bce40165ed"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:f764ba54e33daf20e167915edc443b6f88956f37fb606449b4a5b10ba42235a5"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:1e4b3f8ea6a9cfa8be8484c9221ec0257508e3a1ec43c36acdefb2a9c3b00aa2"}, - {file = "websockets-12.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:9fdf06fd06c32205a07e47328ab49c40fc1407cdec801d698a7c41167ea45113"}, - {file = "websockets-12.0-cp312-cp312-win32.whl", hash = "sha256:baa386875b70cbd81798fa9f71be689c1bf484f65fd6fb08d051a0ee4e79924d"}, - {file = "websockets-12.0-cp312-cp312-win_amd64.whl", hash = "sha256:ae0a5da8f35a5be197f328d4727dbcfafa53d1824fac3d96cdd3a642fe09394f"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:5f6ffe2c6598f7f7207eef9a1228b6f5c818f9f4d53ee920aacd35cec8110438"}, - {file = "websockets-12.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:9edf3fc590cc2ec20dc9d7a45108b5bbaf21c0d89f9fd3fd1685e223771dc0b2"}, - {file = "websockets-12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:8572132c7be52632201a35f5e08348137f658e5ffd21f51f94572ca6c05ea81d"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:604428d1b87edbf02b233e2c207d7d528460fa978f9e391bd8aaf9c8311de137"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1a9d160fd080c6285e202327aba140fc9a0d910b09e423afff4ae5cbbf1c7205"}, - {file = "websockets-12.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87b4aafed34653e465eb77b7c93ef058516cb5acf3eb21e42f33928616172def"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b2ee7288b85959797970114deae81ab41b731f19ebcd3bd499ae9ca0e3f1d2c8"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:7fa3d25e81bfe6a89718e9791128398a50dec6d57faf23770787ff441d851967"}, - {file = "websockets-12.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:a571f035a47212288e3b3519944f6bf4ac7bc7553243e41eac50dd48552b6df7"}, - {file = "websockets-12.0-cp38-cp38-win32.whl", hash = "sha256:3c6cc1360c10c17463aadd29dd3af332d4a1adaa8796f6b0e9f9df1fdb0bad62"}, - {file = "websockets-12.0-cp38-cp38-win_amd64.whl", hash = "sha256:1bf386089178ea69d720f8db6199a0504a406209a0fc23e603b27b300fdd6892"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:ab3d732ad50a4fbd04a4490ef08acd0517b6ae6b77eb967251f4c263011a990d"}, - {file = "websockets-12.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1d9697f3337a89691e3bd8dc56dea45a6f6d975f92e7d5f773bc715c15dde28"}, - {file = "websockets-12.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1df2fbd2c8a98d38a66f5238484405b8d1d16f929bb7a33ed73e4801222a6f53"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:23509452b3bc38e3a057382c2e941d5ac2e01e251acce7adc74011d7d8de434c"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2e5fc14ec6ea568200ea4ef46545073da81900a2b67b3e666f04adf53ad452ec"}, - {file = "websockets-12.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:46e71dbbd12850224243f5d2aeec90f0aaa0f2dde5aeeb8fc8df21e04d99eff9"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b81f90dcc6c85a9b7f29873beb56c94c85d6f0dac2ea8b60d995bd18bf3e2aae"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:a02413bc474feda2849c59ed2dfb2cddb4cd3d2f03a2fedec51d6e959d9b608b"}, - {file = "websockets-12.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:bbe6013f9f791944ed31ca08b077e26249309639313fff132bfbf3ba105673b9"}, - {file = "websockets-12.0-cp39-cp39-win32.whl", hash = "sha256:cbe83a6bbdf207ff0541de01e11904827540aa069293696dd528a6640bd6a5f6"}, - {file = "websockets-12.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc4e7fa5414512b481a2483775a8e8be7803a35b30ca805afa4998a84f9fd9e8"}, - {file = "websockets-12.0-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:248d8e2446e13c1d4326e0a6a4e9629cb13a11195051a73acf414812700badbd"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f44069528d45a933997a6fef143030d8ca8042f0dfaad753e2906398290e2870"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c4e37d36f0d19f0a4413d3e18c0d03d0c268ada2061868c1e6f5ab1a6d575077"}, - {file = "websockets-12.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d829f975fc2e527a3ef2f9c8f25e553eb7bc779c6665e8e1d52aa22800bb38b"}, - {file = "websockets-12.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2c71bd45a777433dd9113847af751aae36e448bc6b8c361a566cb043eda6ec30"}, - {file = "websockets-12.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:0bee75f400895aef54157b36ed6d3b308fcab62e5260703add87f44cee9c82a6"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:423fc1ed29f7512fceb727e2d2aecb952c46aa34895e9ed96071821309951123"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27a5e9964ef509016759f2ef3f2c1e13f403725a5e6a1775555994966a66e931"}, - {file = "websockets-12.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c3181df4583c4d3994d31fb235dc681d2aaad744fbdbf94c4802485ececdecf2"}, - {file = "websockets-12.0-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:b067cb952ce8bf40115f6c19f478dc71c5e719b7fbaa511359795dfd9d1a6468"}, - {file = "websockets-12.0-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:00700340c6c7ab788f176d118775202aadea7602c5cc6be6ae127761c16d6b0b"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e469d01137942849cff40517c97a30a93ae79917752b34029f0ec72df6b46399"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffefa1374cd508d633646d51a8e9277763a9b78ae71324183693959cf94635a7"}, - {file = "websockets-12.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba0cab91b3956dfa9f512147860783a1829a8d905ee218a9837c18f683239611"}, - {file = "websockets-12.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2cb388a5bfb56df4d9a406783b7f9dbefb888c09b71629351cc6b036e9259370"}, - {file = "websockets-12.0-py3-none-any.whl", hash = "sha256:dc284bbc8d7c78a6c69e0c7325ab46ee5e40bb4d50e494d8131a07ef47500e9e"}, - {file = "websockets-12.0.tar.gz", hash = "sha256:81df9cbcbb6c260de1e007e58c011bfebe2dafc8435107b0537f393dd38c8b1b"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a0adf84bc2e7c86e8a202537b4fd50e6f7f0e4a6b6bf64d7ccb96c4cd3330b29"}, + {file = "websockets-14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:90b5d9dfbb6d07a84ed3e696012610b6da074d97453bd01e0e30744b472c8179"}, + {file = "websockets-14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2177ee3901075167f01c5e335a6685e71b162a54a89a56001f1c3e9e3d2ad250"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3f14a96a0034a27f9d47fd9788913924c89612225878f8078bb9d55f859272b0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1f874ba705deea77bcf64a9da42c1f5fc2466d8f14daf410bc7d4ceae0a9fcb0"}, + {file = "websockets-14.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9607b9a442392e690a57909c362811184ea429585a71061cd5d3c2b98065c199"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bea45f19b7ca000380fbd4e02552be86343080120d074b87f25593ce1700ad58"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:219c8187b3ceeadbf2afcf0f25a4918d02da7b944d703b97d12fb01510869078"}, + {file = "websockets-14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad2ab2547761d79926effe63de21479dfaf29834c50f98c4bf5b5480b5838434"}, + {file = "websockets-14.1-cp310-cp310-win32.whl", hash = "sha256:1288369a6a84e81b90da5dbed48610cd7e5d60af62df9851ed1d1d23a9069f10"}, + {file = "websockets-14.1-cp310-cp310-win_amd64.whl", hash = "sha256:e0744623852f1497d825a49a99bfbec9bea4f3f946df6eb9d8a2f0c37a2fec2e"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:449d77d636f8d9c17952628cc7e3b8faf6e92a17ec581ec0c0256300717e1512"}, + {file = "websockets-14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a35f704be14768cea9790d921c2c1cc4fc52700410b1c10948511039be824aac"}, + {file = "websockets-14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b1f3628a0510bd58968c0f60447e7a692933589b791a6b572fcef374053ca280"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c3deac3748ec73ef24fc7be0b68220d14d47d6647d2f85b2771cb35ea847aa1"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7048eb4415d46368ef29d32133134c513f507fff7d953c18c91104738a68c3b3"}, + {file = "websockets-14.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f6cf0ad281c979306a6a34242b371e90e891bce504509fb6bb5246bbbf31e7b6"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cc1fc87428c1d18b643479caa7b15db7d544652e5bf610513d4a3478dbe823d0"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f95ba34d71e2fa0c5d225bde3b3bdb152e957150100e75c86bc7f3964c450d89"}, + {file = "websockets-14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9481a6de29105d73cf4515f2bef8eb71e17ac184c19d0b9918a3701c6c9c4f23"}, + {file = "websockets-14.1-cp311-cp311-win32.whl", hash = "sha256:368a05465f49c5949e27afd6fbe0a77ce53082185bbb2ac096a3a8afaf4de52e"}, + {file = "websockets-14.1-cp311-cp311-win_amd64.whl", hash = "sha256:6d24fc337fc055c9e83414c94e1ee0dee902a486d19d2a7f0929e49d7d604b09"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed907449fe5e021933e46a3e65d651f641975a768d0649fee59f10c2985529ed"}, + {file = "websockets-14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:87e31011b5c14a33b29f17eb48932e63e1dcd3fa31d72209848652310d3d1f0d"}, + {file = "websockets-14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bc6ccf7d54c02ae47a48ddf9414c54d48af9c01076a2e1023e3b486b6e72c707"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9777564c0a72a1d457f0848977a1cbe15cfa75fa2f67ce267441e465717dcf1a"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a655bde548ca98f55b43711b0ceefd2a88a71af6350b0c168aa77562104f3f45"}, + {file = "websockets-14.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a3dfff83ca578cada2d19e665e9c8368e1598d4e787422a460ec70e531dbdd58"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6a6c9bcf7cdc0fd41cc7b7944447982e8acfd9f0d560ea6d6845428ed0562058"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4b6caec8576e760f2c7dd878ba817653144d5f369200b6ddf9771d64385b84d4"}, + {file = "websockets-14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:eb6d38971c800ff02e4a6afd791bbe3b923a9a57ca9aeab7314c21c84bf9ff05"}, + {file = "websockets-14.1-cp312-cp312-win32.whl", hash = "sha256:1d045cbe1358d76b24d5e20e7b1878efe578d9897a25c24e6006eef788c0fdf0"}, + {file = "websockets-14.1-cp312-cp312-win_amd64.whl", hash = "sha256:90f4c7a069c733d95c308380aae314f2cb45bd8a904fb03eb36d1a4983a4993f"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3630b670d5057cd9e08b9c4dab6493670e8e762a24c2c94ef312783870736ab9"}, + {file = "websockets-14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:36ebd71db3b89e1f7b1a5deaa341a654852c3518ea7a8ddfdf69cc66acc2db1b"}, + {file = "websockets-14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5b918d288958dc3fa1c5a0b9aa3256cb2b2b84c54407f4813c45d52267600cd3"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:00fe5da3f037041da1ee0cf8e308374e236883f9842c7c465aa65098b1c9af59"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8149a0f5a72ca36720981418eeffeb5c2729ea55fa179091c81a0910a114a5d2"}, + {file = "websockets-14.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:77569d19a13015e840b81550922056acabc25e3f52782625bc6843cfa034e1da"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cf5201a04550136ef870aa60ad3d29d2a59e452a7f96b94193bee6d73b8ad9a9"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:88cf9163ef674b5be5736a584c999e98daf3aabac6e536e43286eb74c126b9c7"}, + {file = "websockets-14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:836bef7ae338a072e9d1863502026f01b14027250a4545672673057997d5c05a"}, + {file = "websockets-14.1-cp313-cp313-win32.whl", hash = "sha256:0d4290d559d68288da9f444089fd82490c8d2744309113fc26e2da6e48b65da6"}, + {file = "websockets-14.1-cp313-cp313-win_amd64.whl", hash = "sha256:8621a07991add373c3c5c2cf89e1d277e49dc82ed72c75e3afc74bd0acc446f0"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:01bb2d4f0a6d04538d3c5dfd27c0643269656c28045a53439cbf1c004f90897a"}, + {file = "websockets-14.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:414ffe86f4d6f434a8c3b7913655a1a5383b617f9bf38720e7c0799fac3ab1c6"}, + {file = "websockets-14.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8fda642151d5affdee8a430bd85496f2e2517be3a2b9d2484d633d5712b15c56"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd7c11968bc3860d5c78577f0dbc535257ccec41750675d58d8dc66aa47fe52c"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a032855dc7db987dff813583d04f4950d14326665d7e714d584560b140ae6b8b"}, + {file = "websockets-14.1-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b7e7ea2f782408c32d86b87a0d2c1fd8871b0399dd762364c731d86c86069a78"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:39450e6215f7d9f6f7bc2a6da21d79374729f5d052333da4d5825af8a97e6735"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:ceada5be22fa5a5a4cdeec74e761c2ee7db287208f54c718f2df4b7e200b8d4a"}, + {file = "websockets-14.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:3fc753451d471cff90b8f467a1fc0ae64031cf2d81b7b34e1811b7e2691bc4bc"}, + {file = "websockets-14.1-cp39-cp39-win32.whl", hash = "sha256:14839f54786987ccd9d03ed7f334baec0f02272e7ec4f6e9d427ff584aeea8b4"}, + {file = "websockets-14.1-cp39-cp39-win_amd64.whl", hash = "sha256:d9fd19ecc3a4d5ae82ddbfb30962cf6d874ff943e56e0c81f5169be2fda62979"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:e5dc25a9dbd1a7f61eca4b7cb04e74ae4b963d658f9e4f9aad9cd00b688692c8"}, + {file = "websockets-14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:04a97aca96ca2acedf0d1f332c861c5a4486fdcba7bcef35873820f940c4231e"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:df174ece723b228d3e8734a6f2a6febbd413ddec39b3dc592f5a4aa0aff28098"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:034feb9f4286476f273b9a245fb15f02c34d9586a5bc936aff108c3ba1b21beb"}, + {file = "websockets-14.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:660c308dabd2b380807ab64b62985eaccf923a78ebc572bd485375b9ca2b7dc7"}, + {file = "websockets-14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:5a42d3ecbb2db5080fc578314439b1d79eef71d323dc661aa616fb492436af5d"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddaa4a390af911da6f680be8be4ff5aaf31c4c834c1a9147bc21cbcbca2d4370"}, + {file = "websockets-14.1-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:a4c805c6034206143fbabd2d259ec5e757f8b29d0a2f0bf3d2fe5d1f60147a4a"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:205f672a6c2c671a86d33f6d47c9b35781a998728d2c7c2a3e1cf3333fcb62b7"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef440054124728cc49b01c33469de06755e5a7a4e83ef61934ad95fc327fbb0"}, + {file = "websockets-14.1-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e7591d6f440af7f73c4bd9404f3772bfee064e639d2b6cc8c94076e71b2471c1"}, + {file = "websockets-14.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:25225cc79cfebc95ba1d24cd3ab86aaa35bcd315d12fa4358939bd55e9bd74a5"}, + {file = "websockets-14.1-py3-none-any.whl", hash = "sha256:4d4fc827a20abe6d544a119896f6b78ee13fe81cbfef416f3f2ddf09a03f0e2e"}, + {file = "websockets-14.1.tar.gz", hash = "sha256:398b10c77d471c0aab20a845e7a60076b6390bfdaac7a6d2edb0d2c59d75e8d8"}, ] [[package]] @@ -2375,13 +2452,13 @@ h11 = ">=0.9.0,<1" [[package]] name = "zipp" -version = "3.20.1" +version = "3.21.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" files = [ - {file = "zipp-3.20.1-py3-none-any.whl", hash = "sha256:9960cd8967c8f85a56f920d5d507274e74f9ff813a0ab8889a5b5be2daf44064"}, - {file = "zipp-3.20.1.tar.gz", hash = "sha256:c22b14cc4763c5a5b04134207736c107db42e9d3ef2d9779d465f5f1bcba572b"}, + {file = "zipp-3.21.0-py3-none-any.whl", hash = "sha256:ac1bbe05fd2991f160ebce24ffbac5f6d11d83dc90891255885223d42b3cd931"}, + {file = "zipp-3.21.0.tar.gz", hash = "sha256:2c9958f6430a2040341a52eb608ed6dd93ef4392e02ffe219417c1b28b5dd1f4"}, ] [package.extras] @@ -2395,4 +2472,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.0" python-versions = "^3.9,!=3.9.7" -content-hash = "a676df6948689fe5ff0e011484f12ecdde34add2dd2dfca1d290f1d8f8203674" +content-hash = "df35c2022d9529a496d7b66613857683cdf9644f32c45f03467b70ff90d4df30" diff --git a/backend/pyproject.toml b/backend/pyproject.toml index a089a25a..1ee733c5 100644 --- a/backend/pyproject.toml +++ b/backend/pyproject.toml @@ -20,7 +20,7 @@ typer = "^0.9.0" pydantic-settings = "^2.2.1" aiofiles = "^23.2.1" cookiecutter = "^2.6.0" -chatsky = {extras = ["yaml", "telegram"], version = "==0.9.0.dev1"} +chatsky = {extras = ["yaml", "telegram"], version = "0.9.0.dev1"} omegaconf = "^2.3.0" httpx = "^0.27.0" httpx-ws = "^0.6.0" From 372d79d16f3122b871d24174653ea7c0fc1e2ba5 Mon Sep 17 00:00:00 2001 From: Ramimashkouk Date: Mon, 16 Dec 2024 19:03:52 +0800 Subject: [PATCH 41/41] style: Black up --- .../services/json_converter_new2/flow_converter.py | 5 +++-- .../services/json_converter_new2/interface_converter.py | 6 ++---- .../logic_component_converter/condition_converter.py | 6 +++--- .../logic_component_converter/response_converter.py | 4 ++-- .../logic_component_converter/service_replacer.py | 4 ++-- .../services/json_converter_new2/node_converter.py | 8 ++++---- .../services/json_converter_new2/pipeline_converter.py | 7 ++++--- .../services/json_converter_new2/script_converter.py | 2 +- .../services/json_converter_new2/slots_converter.py | 4 ++-- 9 files changed, 23 insertions(+), 23 deletions(-) diff --git a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py index 9b314340..ddbb1aae 100644 --- a/backend/chatsky_ui/services/json_converter_new2/flow_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/flow_converter.py @@ -1,7 +1,8 @@ -from typing import Dict, List, Any, Tuple +from typing import Any, Dict, List, Tuple + from ...schemas.front_graph_components.flow import Flow -from .node_converter import InfoNodeConverter, LinkNodeConverter from .base_converter import BaseConverter +from .node_converter import InfoNodeConverter, LinkNodeConverter class FlowConverter(BaseConverter): diff --git a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py index c5df1e3b..984ac45f 100644 --- a/backend/chatsky_ui/services/json_converter_new2/interface_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/interface_converter.py @@ -1,5 +1,5 @@ -from .base_converter import BaseConverter from ...schemas.front_graph_components.interface import Interface +from .base_converter import BaseConverter class InterfaceConverter(BaseConverter): @@ -10,6 +10,4 @@ def _convert(self): if self.interface.http is not None: return {"chatsky.messengers.HTTPMessengerInterface": {}} elif self.interface.telegram is not None: - return { - "chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}} - } + return {"chatsky.messengers.TelegramInterface": {"token": {"external:os.getenv": "TG_BOT_TOKEN"}}} diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py index d85f2325..a59ce3db 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/condition_converter.py @@ -1,9 +1,9 @@ from abc import ABC, abstractmethod -from ..consts import CUSTOM_FILE, CONDITIONS_FILE -from ..base_converter import BaseConverter -from ....schemas.front_graph_components.info_holders.condition import CustomCondition, SlotCondition from ....core.config import settings +from ....schemas.front_graph_components.info_holders.condition import CustomCondition, SlotCondition +from ..base_converter import BaseConverter +from ..consts import CONDITIONS_FILE, CUSTOM_FILE from .service_replacer import store_custom_service diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py index 2de84a93..cb2624ee 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/response_converter.py @@ -1,7 +1,7 @@ +from ....core.config import settings +from ....schemas.front_graph_components.info_holders.response import CustomResponse, TextResponse from ..base_converter import BaseConverter -from ....schemas.front_graph_components.info_holders.response import TextResponse, CustomResponse from ..consts import CUSTOM_FILE, RESPONSES_FILE -from ....core.config import settings from .service_replacer import store_custom_service diff --git a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py index 4af3dd61..6dee45c1 100644 --- a/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py +++ b/backend/chatsky_ui/services/json_converter_new2/logic_component_converter/service_replacer.py @@ -1,8 +1,8 @@ import ast from ast import NodeTransformer -from typing import Dict, List from pathlib import Path -import logging +from typing import Dict, List + from chatsky_ui.core.logger_config import get_logger diff --git a/backend/chatsky_ui/services/json_converter_new2/node_converter.py b/backend/chatsky_ui/services/json_converter_new2/node_converter.py index fbdc2b84..da4ffa61 100644 --- a/backend/chatsky_ui/services/json_converter_new2/node_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/node_converter.py @@ -1,9 +1,9 @@ -from .base_converter import BaseConverter +from chatsky import PRE_RESPONSE, PRE_TRANSITION, RESPONSE, TRANSITIONS + from ...schemas.front_graph_components.node import InfoNode, LinkNode -from .logic_component_converter.response_converter import TextResponseConverter, CustomResponseConverter +from .base_converter import BaseConverter from .logic_component_converter.condition_converter import CustomConditionConverter, SlotConditionConverter - -from chatsky import RESPONSE, TRANSITIONS, PRE_TRANSITION, PRE_RESPONSE +from .logic_component_converter.response_converter import CustomResponseConverter, TextResponseConverter class NodeConverter(BaseConverter): diff --git a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py index 8efd3040..969640fe 100644 --- a/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/pipeline_converter.py @@ -1,16 +1,17 @@ from pathlib import Path + import yaml try: - from yaml import CLoader as Loader, CDumper as Dumper + from yaml import CDumper as Dumper + from yaml import CLoader as Loader except ImportError: from yaml import Loader, Dumper from ...schemas.front_graph_components.pipeline import Pipeline - from .base_converter import BaseConverter -from .script_converter import ScriptConverter from .interface_converter import InterfaceConverter +from .script_converter import ScriptConverter from .slots_converter import SlotsConverter diff --git a/backend/chatsky_ui/services/json_converter_new2/script_converter.py b/backend/chatsky_ui/services/json_converter_new2/script_converter.py index ac42c499..f1f2197d 100644 --- a/backend/chatsky_ui/services/json_converter_new2/script_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/script_converter.py @@ -1,8 +1,8 @@ from typing import List +from ...schemas.front_graph_components.script import Script from .base_converter import BaseConverter from .flow_converter import FlowConverter -from ...schemas.front_graph_components.script import Script class ScriptConverter(BaseConverter): diff --git a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py index 561e2bab..3bd9970b 100644 --- a/backend/chatsky_ui/services/json_converter_new2/slots_converter.py +++ b/backend/chatsky_ui/services/json_converter_new2/slots_converter.py @@ -1,8 +1,8 @@ from typing import List -from .base_converter import BaseConverter -from ...schemas.front_graph_components.slot import GroupSlot, RegexpSlot from ...schemas.front_graph_components.node import SlotsNode +from ...schemas.front_graph_components.slot import GroupSlot, RegexpSlot +from .base_converter import BaseConverter class SlotsConverter(BaseConverter):