From 7085bad22dddf195892a5f263b83750355ad076a Mon Sep 17 00:00:00 2001 From: eawetchy <10432999+eawetchy@users.noreply.github.com> Date: Tue, 30 Sep 2025 08:55:46 +0100 Subject: [PATCH 1/6] =?UTF-8?q?=F0=9F=90=8D=20Python=20wrapper=20and=20API?= =?UTF-8?q?=20(#2)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Python wrapper and API * Add Python image build workflows * Github Workflow fix * lint * Return type hints * Use TemporaryDirectory in configurable location for uploaded files * Update Author --------- Co-authored-by: ewetchy --- .../workflows/component-container-image.yml | 41 +- .github/workflows/workflow-python.yml | 33 + .../file_checker_python_api/README.md | 0 .../file_checker_api/__init__.py | 1 + .../file_checker_api/app.py | 55 + .../file_checker_python_api/poetry.lock | 393 +++ .../file_checker_python_api/pyproject.toml | 22 + .../file_checker_python_wrapper/.gitignore | 26 + .../file_checker_python_wrapper/README.md | 70 + .../demo_scripts/demo_docker.py | 27 + .../demo_scripts/demo_test.py | 26 + .../file_checker_python_wrapper/poetry.lock | 2413 +++++++++++++++++ .../pyproject.toml | 189 ++ .../__init__.py | 9 + .../file_checker.py | 311 +++ .../argofilechecker_python_wrapper/models.py | 42 + .../tests/conftest.py | 90 + .../3901682_tech_bad_long_name.nc | Bin 0 -> 279562 bytes ...1_meta_PROGRAM_NAME_Not-in_ref-table-41.nc | Bin 0 -> 114903 bytes .../rejected_argo_data/6990661_meta_DOXY_2.nc | Bin 0 -> 269218 bytes .../6990728_tech_BadUnits.nc | Bin 0 -> 175360 bytes .../R6903129_088_QC0_TEMP.nc | Bin 0 -> 267880 bytes .../tests/test_argo_data_validation.py | 103 + .../tests/test_filechecker.py | 34 + .../file_checker_python_wrapper/tox.ini | 64 + python.Dockerfile | 108 + python.README.md | 92 + 27 files changed, 4146 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/workflow-python.yml create mode 100644 file_checker_python/file_checker_python_api/README.md create mode 100644 file_checker_python/file_checker_python_api/file_checker_api/__init__.py create mode 100644 file_checker_python/file_checker_python_api/file_checker_api/app.py create mode 100644 file_checker_python/file_checker_python_api/poetry.lock create mode 100644 file_checker_python/file_checker_python_api/pyproject.toml create mode 100644 file_checker_python/file_checker_python_wrapper/.gitignore create mode 100644 file_checker_python/file_checker_python_wrapper/README.md create mode 100644 file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py create mode 100644 file_checker_python/file_checker_python_wrapper/demo_scripts/demo_test.py create mode 100644 file_checker_python/file_checker_python_wrapper/poetry.lock create mode 100644 file_checker_python/file_checker_python_wrapper/pyproject.toml create mode 100644 file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/__init__.py create mode 100644 file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/file_checker.py create mode 100644 file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/models.py create mode 100644 file_checker_python/file_checker_python_wrapper/tests/conftest.py create mode 100644 file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/3901682_tech_bad_long_name.nc create mode 100644 file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/6903281_meta_PROGRAM_NAME_Not-in_ref-table-41.nc create mode 100644 file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/6990661_meta_DOXY_2.nc create mode 100644 file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/6990728_tech_BadUnits.nc create mode 100644 file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/R6903129_088_QC0_TEMP.nc create mode 100644 file_checker_python/file_checker_python_wrapper/tests/test_argo_data_validation.py create mode 100644 file_checker_python/file_checker_python_wrapper/tests/test_filechecker.py create mode 100644 file_checker_python/file_checker_python_wrapper/tox.ini create mode 100644 python.Dockerfile create mode 100644 python.README.md diff --git a/.github/workflows/component-container-image.yml b/.github/workflows/component-container-image.yml index 68b5542..df4ab07 100644 --- a/.github/workflows/component-container-image.yml +++ b/.github/workflows/component-container-image.yml @@ -11,6 +11,14 @@ on: description: "Path of the docker image Tag" default: "ghcr.io/${{ github.repository }}/app" type: string + target: + description: "Target build stage for Docker multistage build" + required: false + type: string + file: + description: "Path to the Dockerfile." + required: false + type: string jobs: container-image-build: @@ -35,11 +43,20 @@ jobs: password: ${{ secrets.GITHUB_TOKEN }} - name: Build (pull request) uses: docker/build-push-action@v6 - if: ${{ github.event_name == 'pull_request'}} + if: ${{ github.event_name == 'pull_request' && (inputs.target == '' || inputs.target == null) }} with: context: "{{defaultContext}}:${{ inputs.context }}" tags: "${{ steps.format.outputs.lowercase }}:develop" push: false + - name: Build with target (pull request) + uses: docker/build-push-action@v6 + if: ${{ github.event_name == 'pull_request' && inputs.target != '' && inputs.target != null }} + with: + context: "{{defaultContext}}:${{ inputs.context }}" + target: ${{ inputs.target }} + file: ${{ inputs.file }} + tags: "${{ steps.format.outputs.lowercase }}:develop" + push: false - name: Build and push (develop) uses: docker/build-push-action@v6 if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/develop' }} @@ -49,15 +66,33 @@ jobs: push: true - name: Build and push (main) uses: docker/build-push-action@v6 - if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && (inputs.target == '' || inputs.target == null) }} with: context: "{{defaultContext}}:${{ inputs.context }}" tags: "${{ steps.format.outputs.lowercase }}:latest" push: true + - name: Build and push with target (main) + uses: docker/build-push-action@v6 + if: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' && inputs.target != '' && inputs.target != null }} + with: + context: "{{defaultContext}}:${{ inputs.context }}" + target: ${{ inputs.target }} + file: ${{ inputs.file }} + tags: "${{ steps.format.outputs.lowercase }}:latest" + push: true - name: Build and push (release) uses: docker/build-push-action@v6 - if: ${{ github.event_name == 'release' }} + if: ${{ github.event_name == 'release' && (inputs.target == '' || inputs.target == null) }} + with: + context: "{{defaultContext}}:${{ inputs.context }}" + tags: "${{ steps.format.outputs.lowercase }}:${{ github.ref_name }}" + push: true + - name: Build and push with target (release) + uses: docker/build-push-action@v6 + if: ${{ github.event_name == 'release' && inputs.target != '' && inputs.target != null }} with: context: "{{defaultContext}}:${{ inputs.context }}" + target: ${{ inputs.target }} + file: ${{ inputs.file }} tags: "${{ steps.format.outputs.lowercase }}:${{ github.ref_name }}" push: true diff --git a/.github/workflows/workflow-python.yml b/.github/workflows/workflow-python.yml new file mode 100644 index 0000000..78dbe18 --- /dev/null +++ b/.github/workflows/workflow-python.yml @@ -0,0 +1,33 @@ +name: Image build + +on: + push: + branches: + # Run on our main branch + - main + - develop + paths: + - file_checker_python/** + pull_request: + # Run for any pull requests + paths: + - file_checker_python/** + release: + types: [created] + + +jobs: + container-image-build-wrapper: + uses: ./.github/workflows/component-container-image.yml + with: + context: . + file: "python.Dockerfile" + target: file-checker-python + image-path: ghcr.io/OneArgo/ArgoFormatChecker/python-wrapper + container-image-build-api: + uses: ./.github/workflows/component-container-image.yml + with: + context: . + file: "python.Dockerfile" + target: file-checker-api + image-path: ghcr.io/OneArgo/ArgoFormatChecker/python-api \ No newline at end of file diff --git a/file_checker_python/file_checker_python_api/README.md b/file_checker_python/file_checker_python_api/README.md new file mode 100644 index 0000000..e69de29 diff --git a/file_checker_python/file_checker_python_api/file_checker_api/__init__.py b/file_checker_python/file_checker_python_api/file_checker_api/__init__.py new file mode 100644 index 0000000..c07c459 --- /dev/null +++ b/file_checker_python/file_checker_python_api/file_checker_api/__init__.py @@ -0,0 +1 @@ +from .app import app diff --git a/file_checker_python/file_checker_python_api/file_checker_api/app.py b/file_checker_python/file_checker_python_api/file_checker_api/app.py new file mode 100644 index 0000000..eac44a0 --- /dev/null +++ b/file_checker_python/file_checker_python_api/file_checker_api/app.py @@ -0,0 +1,55 @@ +import os +import shutil +from fastapi import FastAPI, UploadFile +from pathlib import Path +from tempfile import TemporaryDirectory + +from argofilechecker_python_wrapper import FileChecker, ValidationResult + +ROOT_PATH = os.getenv("API_ROOT_PATH", "") +UPLOAD_FILES_DIR = Path(os.getenv("UPLOAD_FILES_DIR", Path.cwd())) + +app = FastAPI(root_path=ROOT_PATH) + + +@app.get("/") +def app_status() -> dict[str, str]: + """ + Health check endpoint to confirm that the app is running. + :return: status message + """ + return {"status": "OK"} + + +@app.post("/check-files") +def check_file_list(files: list[UploadFile], dac: str) -> list[ValidationResult]: + """ + Main endpoint to upload files to be checked. + :param files: + List of files uploaded as multipart/form-data + :param dac: + Relevant DAC for the files, e.g. coriolis, bodc, aoml, etc. Must be the same DAC for all files + + :return: + list[ValidationResult] + """ + if not files: + raise ValueError("No files to check.") + if not UPLOAD_FILES_DIR.exists(): + raise FileNotFoundError(f"Upload directory does not exist: {UPLOAD_FILES_DIR}") + if not UPLOAD_FILES_DIR.is_dir(): + raise NotADirectoryError(f"Upload directory path is not a directory: {UPLOAD_FILES_DIR}") + + with TemporaryDirectory(dir=UPLOAD_FILES_DIR) as request_tmp_dir: + request_file_dir = Path(request_tmp_dir) + for upload_file in files: + try: + with request_file_dir.joinpath(upload_file.filename).open("wb") as buffer: + shutil.copyfileobj(upload_file.file, buffer) + finally: + upload_file.file.close() + file_checker = FileChecker() + results = file_checker.check_files(request_file_dir.glob("*"), dac) + if not results: + raise RuntimeError("An error occurred while handling uploaded files.") + return results diff --git a/file_checker_python/file_checker_python_api/poetry.lock b/file_checker_python/file_checker_python_api/poetry.lock new file mode 100644 index 0000000..9de1e4b --- /dev/null +++ b/file_checker_python/file_checker_python_api/poetry.lock @@ -0,0 +1,393 @@ +# This file is automatically @generated by Poetry 2.2.1 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.11.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "anyio-4.11.0-py3-none-any.whl", hash = "sha256:0287e96f4d26d4149305414d4e3bc32f0dcd0862365a4bddea19d7a1ec38c4fc"}, + {file = "anyio-4.11.0.tar.gz", hash = "sha256:82a8d0b81e318cc5ce71a5f1f8b5c4e63619620b63141ef8c995fa0db95a57c4"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.31.0)"] + +[[package]] +name = "click" +version = "8.3.0" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["main"] +files = [ + {file = "click-8.3.0-py3-none-any.whl", hash = "sha256:9b9f285302c6e3064f4330c05f05b81945b2a39544279343e6e7c5f27a9baddc"}, + {file = "click-8.3.0.tar.gz", hash = "sha256:e7b8232224eba16f4ebe410c25ced9f7875cb5f3263ffc93cc3e8da705e229c4"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main"] +markers = "platform_system == \"Windows\"" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastapi" +version = "0.116.2" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "fastapi-0.116.2-py3-none-any.whl", hash = "sha256:c3a7a8fb830b05f7e087d920e0d786ca1fc9892eb4e9a84b227be4c1bc7569db"}, + {file = "fastapi-0.116.2.tar.gz", hash = "sha256:231a6af2fe21cfa2c32730170ad8514985fc250bec16c9b242d3b94c835ef529"}, +] + +[package.dependencies] +pydantic = ">=1.7.4,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0 || >2.0.0,<2.0.1 || >2.0.1,<2.1.0 || >2.1.0,<3.0.0" +starlette = ">=0.40.0,<0.49.0" +typing-extensions = ">=4.8.0" + +[package.extras] +all = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0)", "itsdangerous (>=1.1.0)", "jinja2 (>=3.1.5)", "orjson (>=3.2.1)", "pydantic-extra-types (>=2.0.0)", "pydantic-settings (>=2.0.0)", "python-multipart (>=0.0.18)", "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)"] +standard = ["email-validator (>=2.0.0)", "fastapi-cli[standard] (>=0.0.8)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] +standard-no-fastapi-cloud-cli = ["email-validator (>=2.0.0)", "fastapi-cli[standard-no-fastapi-cloud-cli] (>=0.0.8)", "httpx (>=0.23.0)", "jinja2 (>=3.1.5)", "python-multipart (>=0.0.18)", "uvicorn[standard] (>=0.12.0)"] + +[[package]] +name = "gunicorn" +version = "23.0.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] +tornado = ["tornado (>=0.2)"] + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main"] +files = [ + {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 = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pydantic" +version = "2.11.9" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2"}, + {file = "pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "python-multipart" +version = "0.0.20" +description = "A streaming multipart parser for Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104"}, + {file = "python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "starlette" +version = "0.48.0" +description = "The little ASGI library that shines." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "starlette-0.48.0-py3-none-any.whl", hash = "sha256:0764ca97b097582558ecb498132ed0c7d942f233f365b86ba37770e026510659"}, + {file = "starlette-0.48.0.tar.gz", hash = "sha256:7e8cee469a8ab2352911528110ce9088fdc6a37d9876926e73da7ce4aa4c7a46"}, +] + +[package.dependencies] +anyio = ">=3.6.2,<5" +typing-extensions = {version = ">=4.10.0", markers = "python_version < \"3.13\""} + +[package.extras] +full = ["httpx (>=0.27.0,<0.29.0)", "itsdangerous", "jinja2", "python-multipart (>=0.0.18)", "pyyaml"] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "uvicorn" +version = "0.35.0" +description = "The lightning-fast ASGI server." +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a"}, + {file = "uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01"}, +] + +[package.dependencies] +click = ">=7.0" +h11 = ">=0.8" +typing-extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} + +[package.extras] +standard = ["colorama (>=0.4) ; sys_platform == \"win32\"", "httptools (>=0.6.3)", "python-dotenv (>=0.13)", "pyyaml (>=5.1)", "uvloop (>=0.15.1) ; sys_platform != \"win32\" and sys_platform != \"cygwin\" and platform_python_implementation != \"PyPy\"", "watchfiles (>=0.13)", "websockets (>=10.4)"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<4.0" +content-hash = "6463ebe75ac1cfdfacbe098134e7d8afd2fe2a9e53486d457e3ca2c245e78359" diff --git a/file_checker_python/file_checker_python_api/pyproject.toml b/file_checker_python/file_checker_python_api/pyproject.toml new file mode 100644 index 0000000..0ce310b --- /dev/null +++ b/file_checker_python/file_checker_python_api/pyproject.toml @@ -0,0 +1,22 @@ +[project] +name = "file-checker-api" +version = "0.0.0" +description = "" +authors = [ + {name = "Elisabeth Wetchy", email = "Elisabeth.Wetchy@noc.ac.uk"} +] +readme = "README.md" +requires-python = ">=3.10,<4.0" +dependencies = [ + "fastapi (>=0.116.2,<0.117.0)", + "gunicorn (>=23.0.0,<24.0.0)", + "uvicorn (>=0.35.0,<0.36.0)", + "python-multipart (>=0.0.20,<0.0.21)" +] + +[tool.poetry] +packages = [{include = "file_checker_api"}] + +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file diff --git a/file_checker_python/file_checker_python_wrapper/.gitignore b/file_checker_python/file_checker_python_wrapper/.gitignore new file mode 100644 index 0000000..820ba55 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/.gitignore @@ -0,0 +1,26 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] + +# Distribution / packaging +build/ +dist/ +public/ +*.egg-info/ +.eggs/ +docs/source/generated + +# Test artifacts= + +.coverage +coverage.xml +coverage_reports +junit.xml + +# Developer Environments +venv/ +.tox/ +./ruff_cache +./mypy_cache +.env +secrets.env diff --git a/file_checker_python/file_checker_python_wrapper/README.md b/file_checker_python/file_checker_python_wrapper/README.md new file mode 100644 index 0000000..7794933 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/README.md @@ -0,0 +1,70 @@ +# ArgoFileChecker Python Wrapper + +A lightweight Python wrapper around the **Argo NetCDF File Checker**. +It runs the File Checker JAR as a **subprocess**, parses the generated XML output files (which are generated in a temporary folder), and returns typed `ValidationResult` objects. + +## Installation + +### With Poetry + +```bash +poetry add argofilechecker-python-wrapper +``` + +## Run ArgoFileChecker Python Wrapper (after installing the package and any additional dependencies) +The wrapper can receive paths explicitly or through environment variables: + +FILE_CHECKER_JAR: path to file_checker_exec-*.jar + +FILE_CHECKER_SPECS: path to the file_checker_spec directory + +### Usage example +See /demo_scripts where a demo python script is provided along with a file checker .jar and some netcdf test data. + +```bash +cd ./demo_scripts +poetry run python demo_test.py +``` + +## Run ArgoFileChecker Python Wrapper in a pre-built container image + +### build and run the image + +```bash +docker build -t argofilechecker-python:latest . +``` + +Argo File checker .jar file will be included in the docker image but you still need to mount your data and specs volumes and also your script file (if not used in interactive mode) : + +```bash +cd ./demo_scripts +docker run --rm -v ${pwd}/demo_docker.py:/scripts/demo_docker.py -v ${pwd}/test_data/2903996:/data -v ${pwd}/file_checker_spec:/specs argofilechecker-python:latest /scripts/demo_docker.py +``` +Ensure that the correct volumes names are used in your script. + +You can use interactive mode to execute python code inside the container : + +```bash +cd ./demo_scripts +docker run --rm -it -v ${pwd}/test_data/2903996:/data -v ${pwd}/file_checker_spec:/specs argofilechecker-python:latest +>>> from argofilechecker_python_wrapper import FileChecker +>>> filechecker = FileChecker(specs_path='/specs') +>>> results = filechecker.check_files(['/data/2903996_meta.nc'],"coriolis") +>>> results[0].to_string() +'/data/2903996_meta.nc : FILE ACCEPTED with 0 error(s) and 0 warning(s)' +``` + + +### Results Values + +- ResultType.SUCCESS → the file is accepted by the File Checker. + +- ResultType.FAILURE → the file is rejected (errors found). + +- ResultType.ERROR → internal error in the checker or parsing failure. + +The phase (PhaseType) indicates the stage where the error occurred: opening, format check, data validation, or file name check. + +Errors and warnings's number and messages can be accessed also. + +For more information see models.py \ No newline at end of file diff --git a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py new file mode 100644 index 0000000..2abefc4 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py @@ -0,0 +1,27 @@ +"""Demo script to use argofilechecker_python_wrapper in docker container.""" + +import os +from typing import List + +from argofilechecker_python_wrapper import FileChecker, ValidationResult +from argofilechecker_python_wrapper.models import ResultType + +specs_path = "/app/specs" + + +# 1) Instantiate the wrapper (explicit paths). +# file checker jar is already contained in the docker image +file_checker = FileChecker(specs_path=specs_path) + + +# 2) Validate a list of files from the same DAC +list_files = [f"/data/{file}" for file in os.listdir("/data")] +validation_results: List[ValidationResult] = file_checker.check_files(list_files, "coriolis") + +# 3) Iterate over the results +for file_result in validation_results: + print(file_result.to_string()) + + if file_result.result in {ResultType.FAILURE, ResultType.ERROR}: + print(*file_result.errors_messages) + print(*file_result.warnings_messages) diff --git a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_test.py b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_test.py new file mode 100644 index 0000000..06e62b4 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_test.py @@ -0,0 +1,26 @@ +"""Demo script to use argofilechecker_python_wrapper.""" + +import os +from typing import List + +from argofilechecker_python_wrapper import FileChecker, ValidationResult +from argofilechecker_python_wrapper.models import ResultType + +jar_path = "./file_checker_exec-2.9.3-SNAPSHOT.jar" +spec_path = "./file_checker_spec" + + +# 1) Instantiate the wrapper (explicit paths) +file_checker = FileChecker(jar_path, spec_path) + +# 2) Validate a list of files from the same DAC +list_files = [f"./test_data/2903996/{file}" for file in os.listdir("./test_data/2903996")] +validation_results: List[ValidationResult] = file_checker.check_files(list_files, "coriolis") + +# 3) Iterate over the results +for file_result in validation_results: + print(file_result.to_string()) + + if file_result.result in {ResultType.FAILURE, ResultType.ERROR}: + print(*file_result.errors_messages) + print(*file_result.warnings_messages) diff --git a/file_checker_python/file_checker_python_wrapper/poetry.lock b/file_checker_python/file_checker_python_wrapper/poetry.lock new file mode 100644 index 0000000..500e20c --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/poetry.lock @@ -0,0 +1,2413 @@ +# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. + +[[package]] +name = "annotated-types" +version = "0.7.0" +description = "Reusable constraint types to use with typing.Annotated" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53"}, + {file = "annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89"}, +] + +[[package]] +name = "anyio" +version = "4.10.0" +description = "High-level concurrency and networking framework on top of asyncio or Trio" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "anyio-4.10.0-py3-none-any.whl", hash = "sha256:60e474ac86736bbfd6f210f7a61218939c318f43f9972497381f1c5e930ed3d1"}, + {file = "anyio-4.10.0.tar.gz", hash = "sha256:3f3fae35c96039744587aa5b8371e7e8e603c0702999535961dd336026973ba6"}, +] + +[package.dependencies] +exceptiongroup = {version = ">=1.0.2", markers = "python_version < \"3.11\""} +idna = ">=2.8" +sniffio = ">=1.1" +typing_extensions = {version = ">=4.5", markers = "python_version < \"3.13\""} + +[package.extras] +trio = ["trio (>=0.26.1)"] + +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version < \"3.12\""} + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + +[[package]] +name = "bandit" +version = "1.8.6" +description = "Security oriented static analyser for python code." +optional = false +python-versions = ">=3.9" +groups = ["main", "bandit"] +files = [ + {file = "bandit-1.8.6-py3-none-any.whl", hash = "sha256:3348e934d736fcdb68b6aa4030487097e23a501adf3e7827b63658df464dddd0"}, + {file = "bandit-1.8.6.tar.gz", hash = "sha256:dbfe9c25fc6961c2078593de55fd19f2559f9e45b99f1272341f5b95dea4e56b"}, +] + +[package.dependencies] +colorama = {version = ">=0.3.9", markers = "platform_system == \"Windows\""} +PyYAML = ">=5.3.1" +rich = "*" +stevedore = ">=1.20.0" +tomli = {version = ">=1.1.0", optional = true, markers = "python_version < \"3.11\" and extra == \"toml\""} + +[package.extras] +baseline = ["GitPython (>=3.1.30)"] +sarif = ["jschema-to-python (>=1.2.3)", "sarif-om (>=1.0.4)"] +test = ["beautifulsoup4 (>=4.8.0)", "coverage (>=4.5.4)", "fixtures (>=3.0.0)", "flake8 (>=4.0.0)", "pylint (==1.9.4)", "stestr (>=2.5.0)", "testscenarios (>=0.5.0)", "testtools (>=2.3.0)"] +toml = ["tomli (>=1.1.0) ; python_version < \"3.11\""] +yaml = ["PyYAML"] + +[[package]] +name = "build" +version = "1.3.0" +description = "A simple, correct Python build frontend" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4"}, + {file = "build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "os_name == \"nt\""} +importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} +packaging = ">=19.1" +pyproject_hooks = "*" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} + +[package.extras] +uv = ["uv (>=0.1.18)"] +virtualenv = ["virtualenv (>=20.11) ; python_version < \"3.10\"", "virtualenv (>=20.17) ; python_version >= \"3.10\" and python_version < \"3.14\"", "virtualenv (>=20.31) ; python_version >= \"3.14\""] + +[[package]] +name = "cachecontrol" +version = "0.14.3" +description = "httplib2 caching for requests" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "cachecontrol-0.14.3-py3-none-any.whl", hash = "sha256:b35e44a3113f17d2a31c1e6b27b9de6d4405f84ae51baa8c1d3cc5b633010cae"}, + {file = "cachecontrol-0.14.3.tar.gz", hash = "sha256:73e7efec4b06b20d9267b441c1f733664f989fb8688391b670ca812d70795d11"}, +] + +[package.dependencies] +filelock = {version = ">=3.8.0", optional = true, markers = "extra == \"filecache\""} +msgpack = ">=0.5.2,<2.0.0" +requests = ">=2.16.0" + +[package.extras] +dev = ["CacheControl[filecache,redis]", "build", "cherrypy", "codespell[tomli]", "furo", "mypy", "pytest", "pytest-cov", "ruff", "sphinx", "sphinx-copybutton", "tox", "types-redis", "types-requests"] +filecache = ["filelock (>=3.8.0)"] +redis = ["redis (>=2.10.5)"] + +[[package]] +name = "cachetools" +version = "6.2.0" +description = "Extensible memoizing collections and decorators" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "cachetools-6.2.0-py3-none-any.whl", hash = "sha256:1c76a8960c0041fcc21097e357f882197c79da0dbff766e7317890a65d7d8ba6"}, + {file = "cachetools-6.2.0.tar.gz", hash = "sha256:38b328c0889450f05f5e120f56ab68c8abaf424e1275522b138ffc93253f7e32"}, +] + +[[package]] +name = "certifi" +version = "2025.8.3" +description = "Python package for providing Mozilla's CA Bundle." +optional = false +python-versions = ">=3.7" +groups = ["main", "build"] +files = [ + {file = "certifi-2025.8.3-py3-none-any.whl", hash = "sha256:f6c12493cfb1b06ba2ff328595af9350c65d6644968e5d3a2ffd78699af217a5"}, + {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, +] + +[[package]] +name = "cffi" +version = "2.0.0" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, + {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, + {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, + {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, + {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, + {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, + {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, + {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, + {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, + {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, + {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, + {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, + {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, + {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, + {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, + {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, + {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, + {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, + {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, + {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, + {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, + {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, + {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, + {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, + {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, + {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, + {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, + {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, + {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, + {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, + {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, + {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, + {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, + {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, + {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, + {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, + {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, + {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, + {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, + {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, + {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, + {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" or extra == \"build\" and sys_platform == \"darwin\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\""} + +[package.dependencies] +pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} + +[[package]] +name = "chardet" +version = "5.2.0" +description = "Universal encoding detector for Python 3" +optional = false +python-versions = ">=3.7" +groups = ["main", "test"] +files = [ + {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, + {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, +] + +[[package]] +name = "charset-normalizer" +version = "3.4.3" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +optional = false +python-versions = ">=3.7" +groups = ["main", "build"] +files = [ + {file = "charset_normalizer-3.4.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb7f67a1bfa6e40b438170ebdc8158b78dc465a5a67b6dde178a46987b244a72"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc9370a2da1ac13f0153780040f465839e6cccb4a1e44810124b4e22483c93fe"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:07a0eae9e2787b586e129fdcbe1af6997f8d0e5abaa0bc98c0e20e124d67e601"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:74d77e25adda8581ffc1c720f1c81ca082921329452eba58b16233ab1842141c"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d0e909868420b7049dafd3a31d45125b31143eec59235311fc4c57ea26a4acd2"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:c6f162aabe9a91a309510d74eeb6507fab5fff92337a15acbe77753d88d9dcf0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:4ca4c094de7771a98d7fbd67d9e5dbf1eb73efa4f744a730437d8a3a5cf994f0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:02425242e96bcf29a49711b0ca9f37e451da7c70562bc10e8ed992a5a7a25cc0"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:78deba4d8f9590fe4dae384aeff04082510a709957e968753ff3c48399f6f92a"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win32.whl", hash = "sha256:d79c198e27580c8e958906f803e63cddb77653731be08851c7df0b1a14a8fc0f"}, + {file = "charset_normalizer-3.4.3-cp310-cp310-win_amd64.whl", hash = "sha256:c6e490913a46fa054e03699c70019ab869e990270597018cef1d8562132c2669"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:b256ee2e749283ef3ddcff51a675ff43798d92d746d1a6e4631bf8c707d22d0b"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:13faeacfe61784e2559e690fc53fa4c5ae97c6fcedb8eb6fb8d0a15b475d2c64"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:00237675befef519d9af72169d8604a067d92755e84fe76492fef5441db05b91"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:585f3b2a80fbd26b048a0be90c5aae8f06605d3c92615911c3a2b03a8a3b796f"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0e78314bdc32fa80696f72fa16dc61168fda4d6a0c014e0380f9d02f0e5d8a07"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:96b2b3d1a83ad55310de8c7b4a2d04d9277d5591f40761274856635acc5fcb30"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:939578d9d8fd4299220161fdd76e86c6a251987476f5243e8864a7844476ba14"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:fd10de089bcdcd1be95a2f73dbe6254798ec1bda9f450d5828c96f93e2536b9c"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:1e8ac75d72fa3775e0b7cb7e4629cec13b7514d928d15ef8ea06bca03ef01cae"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win32.whl", hash = "sha256:6cf8fd4c04756b6b60146d98cd8a77d0cdae0e1ca20329da2ac85eed779b6849"}, + {file = "charset_normalizer-3.4.3-cp311-cp311-win_amd64.whl", hash = "sha256:31a9a6f775f9bcd865d88ee350f0ffb0e25936a7f930ca98995c05abf1faf21c"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:e28e334d3ff134e88989d90ba04b47d84382a828c061d0d1027b1b12a62b39b1"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0cacf8f7297b0c4fcb74227692ca46b4a5852f8f4f24b3c766dd94a1075c4884"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c6fd51128a41297f5409deab284fecbe5305ebd7e5a1f959bee1c054622b7018"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3cfb2aad70f2c6debfbcb717f23b7eb55febc0bb23dcffc0f076009da10c6392"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1606f4a55c0fd363d754049cdf400175ee96c992b1f8018b993941f221221c5f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:027b776c26d38b7f15b26a5da1044f376455fb3766df8fc38563b4efbc515154"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:42e5088973e56e31e4fa58eb6bd709e42fc03799c11c42929592889a2e54c491"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:cc34f233c9e71701040d772aa7490318673aa7164a0efe3172b2981218c26d93"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:320e8e66157cc4e247d9ddca8e21f427efc7a04bbd0ac8a9faf56583fa543f9f"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win32.whl", hash = "sha256:fb6fecfd65564f208cbf0fba07f107fb661bcd1a7c389edbced3f7a493f70e37"}, + {file = "charset_normalizer-3.4.3-cp312-cp312-win_amd64.whl", hash = "sha256:86df271bf921c2ee3818f0522e9a5b8092ca2ad8b065ece5d7d9d0e9f4849bcc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:14c2a87c65b351109f6abfc424cab3927b3bdece6f706e4d12faaf3d52ee5efe"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:41d1fc408ff5fdfb910200ec0e74abc40387bccb3252f3f27c0676731df2b2c8"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1bb60174149316da1c35fa5233681f7c0f9f514509b8e399ab70fea5f17e45c9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:30d006f98569de3459c2fc1f2acde170b7b2bd265dc1943e87e1a4efe1b67c31"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:416175faf02e4b0810f1f38bcb54682878a4af94059a1cd63b8747244420801f"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:6aab0f181c486f973bc7262a97f5aca3ee7e1437011ef0c2ec04b5a11d16c927"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabf8315679312cfa71302f9bd509ded4f2f263fb5b765cf1433b39106c3cc9"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:bd28b817ea8c70215401f657edef3a8aa83c29d447fb0b622c35403780ba11d5"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:18343b2d246dc6761a249ba1fb13f9ee9a2bcd95decc767319506056ea4ad4dc"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win32.whl", hash = "sha256:6fb70de56f1859a3f71261cbe41005f56a7842cc348d3aeb26237560bfa5e0ce"}, + {file = "charset_normalizer-3.4.3-cp313-cp313-win_amd64.whl", hash = "sha256:cf1ebb7d78e1ad8ec2a8c4732c7be2e736f6e5123a4146c5b89c9d1f585f8cef"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-macosx_10_13_universal2.whl", hash = "sha256:3cd35b7e8aedeb9e34c41385fda4f73ba609e561faedfae0a9e75e44ac558a15"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b89bc04de1d83006373429975f8ef9e7932534b8cc9ca582e4db7d20d91816db"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2001a39612b241dae17b4687898843f254f8748b796a2e16f1051a17078d991d"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:8dcfc373f888e4fb39a7bc57e93e3b845e7f462dacc008d9749568b1c4ece096"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:18b97b8404387b96cdbd30ad660f6407799126d26a39ca65729162fd810a99aa"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ccf600859c183d70eb47e05a44cd80a4ce77394d1ac0f79dbd2dd90a69a3a049"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:53cd68b185d98dde4ad8990e56a58dea83a4162161b1ea9272e5c9182ce415e0"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:30a96e1e1f865f78b030d65241c1ee850cdf422d869e9028e2fc1d5e4db73b92"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:d716a916938e03231e86e43782ca7878fb602a125a91e7acb8b5112e2e96ac16"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win32.whl", hash = "sha256:c6dbd0ccdda3a2ba7c2ecd9d77b37f3b5831687d8dc1b6ca5f56a4880cc7b7ce"}, + {file = "charset_normalizer-3.4.3-cp314-cp314-win_amd64.whl", hash = "sha256:73dc19b562516fc9bcf6e5d6e596df0b4eb98d87e4f79f3ae71840e6ed21361c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:0f2be7e0cf7754b9a30eb01f4295cc3d4358a479843b31f328afd210e2c7598c"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c60e092517a73c632ec38e290eba714e9627abe9d301c8c8a12ec32c314a2a4b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:252098c8c7a873e17dd696ed98bbe91dbacd571da4b87df3736768efa7a792e4"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3653fad4fe3ed447a596ae8638b437f827234f01a8cd801842e43f3d0a6b281b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8999f965f922ae054125286faf9f11bc6932184b93011d138925a1773830bbe9"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:d95bfb53c211b57198bb91c46dd5a2d8018b3af446583aab40074bf7988401cb"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:5b413b0b1bfd94dbf4023ad6945889f374cd24e3f62de58d6bb102c4d9ae534a"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:b5e3b2d152e74e100a9e9573837aba24aab611d39428ded46f4e4022ea7d1942"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:a2d08ac246bb48479170408d6c19f6385fa743e7157d716e144cad849b2dd94b"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win32.whl", hash = "sha256:ec557499516fc90fd374bf2e32349a2887a876fbf162c160e3c01b6849eaf557"}, + {file = "charset_normalizer-3.4.3-cp38-cp38-win_amd64.whl", hash = "sha256:5d8d01eac18c423815ed4f4a2ec3b439d654e55ee4ad610e153cf02faf67ea40"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:70bfc5f2c318afece2f5838ea5e4c3febada0be750fcf4775641052bbba14d05"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:23b6b24d74478dc833444cbd927c338349d6ae852ba53a0d02a2de1fce45b96e"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:34a7f768e3f985abdb42841e20e17b330ad3aaf4bb7e7aeeb73db2e70f077b99"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:fb731e5deb0c7ef82d698b0f4c5bb724633ee2a489401594c5c88b02e6cb15f7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:257f26fed7d7ff59921b78244f3cd93ed2af1800ff048c33f624c87475819dd7"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1ef99f0456d3d46a50945c98de1774da86f8e992ab5c77865ea8b8195341fc19"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2c322db9c8c89009a990ef07c3bcc9f011a3269bc06782f916cd3d9eed7c9312"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:511729f456829ef86ac41ca78c63a5cb55240ed23b4b737faca0eb1abb1c41bc"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:88ab34806dea0671532d3f82d82b85e8fc23d7b2dd12fa837978dad9bb392a34"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win32.whl", hash = "sha256:16a8770207946ac75703458e2c743631c79c59c5890c80011d536248f8eaa432"}, + {file = "charset_normalizer-3.4.3-cp39-cp39-win_amd64.whl", hash = "sha256:d22dbedd33326a4a5190dd4fe9e9e693ef12160c77382d9e87919bce54f3d4ca"}, + {file = "charset_normalizer-3.4.3-py3-none-any.whl", hash = "sha256:ce571ab16d890d23b5c278547ba694193a45011ff86a9162a71307ed9f86759a"}, + {file = "charset_normalizer-3.4.3.tar.gz", hash = "sha256:6fce4b8500244f6fcb71465d4a4930d132ba9ab8e71a7859e6a5d59851068d14"}, +] + +[[package]] +name = "cleo" +version = "2.1.0" +description = "Cleo allows you to create beautiful and testable command-line interfaces." +optional = true +python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "cleo-2.1.0-py3-none-any.whl", hash = "sha256:4a31bd4dd45695a64ee3c4758f583f134267c2bc518d8ae9a29cf237d009b07e"}, + {file = "cleo-2.1.0.tar.gz", hash = "sha256:0b2c880b5d13660a7ea651001fb4acb527696c01f15c9ee650f377aa543fd523"}, +] + +[package.dependencies] +crashtest = ">=0.4.1,<0.5.0" +rapidfuzz = ">=3.0.0,<4.0.0" + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +groups = ["main", "bandit", "test"] +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] +markers = {bandit = "platform_system == \"Windows\""} + +[[package]] +name = "coverage" +version = "7.10.6" +description = "Code coverage measurement for Python" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "coverage-7.10.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:70e7bfbd57126b5554aa482691145f798d7df77489a177a6bef80de78860a356"}, + {file = "coverage-7.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e41be6f0f19da64af13403e52f2dec38bbc2937af54df8ecef10850ff8d35301"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c61fc91ab80b23f5fddbee342d19662f3d3328173229caded831aa0bd7595460"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:10356fdd33a7cc06e8051413140bbdc6f972137508a3572e3f59f805cd2832fd"}, + {file = "coverage-7.10.6-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:80b1695cf7c5ebe7b44bf2521221b9bb8cdf69b1f24231149a7e3eb1ae5fa2fb"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2e4c33e6378b9d52d3454bd08847a8651f4ed23ddbb4a0520227bd346382bbc6"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:c8a3ec16e34ef980a46f60dc6ad86ec60f763c3f2fa0db6d261e6e754f72e945"}, + {file = "coverage-7.10.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7d79dabc0a56f5af990cc6da9ad1e40766e82773c075f09cc571e2076fef882e"}, + {file = "coverage-7.10.6-cp310-cp310-win32.whl", hash = "sha256:86b9b59f2b16e981906e9d6383eb6446d5b46c278460ae2c36487667717eccf1"}, + {file = "coverage-7.10.6-cp310-cp310-win_amd64.whl", hash = "sha256:e132b9152749bd33534e5bd8565c7576f135f157b4029b975e15ee184325f528"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c706db3cabb7ceef779de68270150665e710b46d56372455cd741184f3868d8f"}, + {file = "coverage-7.10.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:8e0c38dc289e0508ef68ec95834cb5d2e96fdbe792eaccaa1bccac3966bbadcc"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:752a3005a1ded28f2f3a6e8787e24f28d6abe176ca64677bcd8d53d6fe2ec08a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:689920ecfd60f992cafca4f5477d55720466ad2c7fa29bb56ac8d44a1ac2b47a"}, + {file = "coverage-7.10.6-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ec98435796d2624d6905820a42f82149ee9fc4f2d45c2c5bc5a44481cc50db62"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b37201ce4a458c7a758ecc4efa92fa8ed783c66e0fa3c42ae19fc454a0792153"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2904271c80898663c810a6b067920a61dd8d38341244a3605bd31ab55250dad5"}, + {file = "coverage-7.10.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5aea98383463d6e1fa4e95416d8de66f2d0cb588774ee20ae1b28df826bcb619"}, + {file = "coverage-7.10.6-cp311-cp311-win32.whl", hash = "sha256:e3fb1fa01d3598002777dd259c0c2e6d9d5e10e7222976fc8e03992f972a2cba"}, + {file = "coverage-7.10.6-cp311-cp311-win_amd64.whl", hash = "sha256:f35ed9d945bece26553d5b4c8630453169672bea0050a564456eb88bdffd927e"}, + {file = "coverage-7.10.6-cp311-cp311-win_arm64.whl", hash = "sha256:99e1a305c7765631d74b98bf7dbf54eeea931f975e80f115437d23848ee8c27c"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:5b2dd6059938063a2c9fee1af729d4f2af28fd1a545e9b7652861f0d752ebcea"}, + {file = "coverage-7.10.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:388d80e56191bf846c485c14ae2bc8898aa3124d9d35903fef7d907780477634"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:90cb5b1a4670662719591aa92d0095bb41714970c0b065b02a2610172dbf0af6"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:961834e2f2b863a0e14260a9a273aff07ff7818ab6e66d2addf5628590c628f9"}, + {file = "coverage-7.10.6-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:bf9a19f5012dab774628491659646335b1928cfc931bf8d97b0d5918dd58033c"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:99c4283e2a0e147b9c9cc6bc9c96124de9419d6044837e9799763a0e29a7321a"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:282b1b20f45df57cc508c1e033403f02283adfb67d4c9c35a90281d81e5c52c5"}, + {file = "coverage-7.10.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:8cdbe264f11afd69841bd8c0d83ca10b5b32853263ee62e6ac6a0ab63895f972"}, + {file = "coverage-7.10.6-cp312-cp312-win32.whl", hash = "sha256:a517feaf3a0a3eca1ee985d8373135cfdedfbba3882a5eab4362bda7c7cf518d"}, + {file = "coverage-7.10.6-cp312-cp312-win_amd64.whl", hash = "sha256:856986eadf41f52b214176d894a7de05331117f6035a28ac0016c0f63d887629"}, + {file = "coverage-7.10.6-cp312-cp312-win_arm64.whl", hash = "sha256:acf36b8268785aad739443fa2780c16260ee3fa09d12b3a70f772ef100939d80"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ffea0575345e9ee0144dfe5701aa17f3ba546f8c3bb48db62ae101afb740e7d6"}, + {file = "coverage-7.10.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:95d91d7317cde40a1c249d6b7382750b7e6d86fad9d8eaf4fa3f8f44cf171e80"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3e23dd5408fe71a356b41baa82892772a4cefcf758f2ca3383d2aa39e1b7a003"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:0f3f56e4cb573755e96a16501a98bf211f100463d70275759e73f3cbc00d4f27"}, + {file = "coverage-7.10.6-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:db4a1d897bbbe7339946ffa2fe60c10cc81c43fab8b062d3fcb84188688174a4"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d8fd7879082953c156d5b13c74aa6cca37f6a6f4747b39538504c3f9c63d043d"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:28395ca3f71cd103b8c116333fa9db867f3a3e1ad6a084aa3725ae002b6583bc"}, + {file = "coverage-7.10.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:61c950fc33d29c91b9e18540e1aed7d9f6787cc870a3e4032493bbbe641d12fc"}, + {file = "coverage-7.10.6-cp313-cp313-win32.whl", hash = "sha256:160c00a5e6b6bdf4e5984b0ef21fc860bc94416c41b7df4d63f536d17c38902e"}, + {file = "coverage-7.10.6-cp313-cp313-win_amd64.whl", hash = "sha256:628055297f3e2aa181464c3808402887643405573eb3d9de060d81531fa79d32"}, + {file = "coverage-7.10.6-cp313-cp313-win_arm64.whl", hash = "sha256:df4ec1f8540b0bcbe26ca7dd0f541847cc8a108b35596f9f91f59f0c060bfdd2"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:c9a8b7a34a4de3ed987f636f71881cd3b8339f61118b1aa311fbda12741bff0b"}, + {file = "coverage-7.10.6-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:8dd5af36092430c2b075cee966719898f2ae87b636cefb85a653f1d0ba5d5393"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b0353b0f0850d49ada66fdd7d0c7cdb0f86b900bb9e367024fd14a60cecc1e27"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:d6b9ae13d5d3e8aeca9ca94198aa7b3ebbc5acfada557d724f2a1f03d2c0b0df"}, + {file = "coverage-7.10.6-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:675824a363cc05781b1527b39dc2587b8984965834a748177ee3c37b64ffeafb"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:692d70ea725f471a547c305f0d0fc6a73480c62fb0da726370c088ab21aed282"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:851430a9a361c7a8484a36126d1d0ff8d529d97385eacc8dfdc9bfc8c2d2cbe4"}, + {file = "coverage-7.10.6-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:d9369a23186d189b2fc95cc08b8160ba242057e887d766864f7adf3c46b2df21"}, + {file = "coverage-7.10.6-cp313-cp313t-win32.whl", hash = "sha256:92be86fcb125e9bda0da7806afd29a3fd33fdf58fba5d60318399adf40bf37d0"}, + {file = "coverage-7.10.6-cp313-cp313t-win_amd64.whl", hash = "sha256:6b3039e2ca459a70c79523d39347d83b73f2f06af5624905eba7ec34d64d80b5"}, + {file = "coverage-7.10.6-cp313-cp313t-win_arm64.whl", hash = "sha256:3fb99d0786fe17b228eab663d16bee2288e8724d26a199c29325aac4b0319b9b"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:6008a021907be8c4c02f37cdc3ffb258493bdebfeaf9a839f9e71dfdc47b018e"}, + {file = "coverage-7.10.6-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:5e75e37f23eb144e78940b40395b42f2321951206a4f50e23cfd6e8a198d3ceb"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0f7cb359a448e043c576f0da00aa8bfd796a01b06aa610ca453d4dde09cc1034"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c68018e4fc4e14b5668f1353b41ccf4bc83ba355f0e1b3836861c6f042d89ac1"}, + {file = "coverage-7.10.6-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cd4b2b0707fc55afa160cd5fc33b27ccbf75ca11d81f4ec9863d5793fc6df56a"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:4cec13817a651f8804a86e4f79d815b3b28472c910e099e4d5a0e8a3b6a1d4cb"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f2a6a8e06bbda06f78739f40bfb56c45d14eb8249d0f0ea6d4b3d48e1f7c695d"}, + {file = "coverage-7.10.6-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:081b98395ced0d9bcf60ada7661a0b75f36b78b9d7e39ea0790bb4ed8da14747"}, + {file = "coverage-7.10.6-cp314-cp314-win32.whl", hash = "sha256:6937347c5d7d069ee776b2bf4e1212f912a9f1f141a429c475e6089462fcecc5"}, + {file = "coverage-7.10.6-cp314-cp314-win_amd64.whl", hash = "sha256:adec1d980fa07e60b6ef865f9e5410ba760e4e1d26f60f7e5772c73b9a5b0713"}, + {file = "coverage-7.10.6-cp314-cp314-win_arm64.whl", hash = "sha256:a80f7aef9535442bdcf562e5a0d5a5538ce8abe6bb209cfbf170c462ac2c2a32"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:0de434f4fbbe5af4fa7989521c655c8c779afb61c53ab561b64dcee6149e4c65"}, + {file = "coverage-7.10.6-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:6e31b8155150c57e5ac43ccd289d079eb3f825187d7c66e755a055d2c85794c6"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:98cede73eb83c31e2118ae8d379c12e3e42736903a8afcca92a7218e1f2903b0"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:f863c08f4ff6b64fa8045b1e3da480f5374779ef187f07b82e0538c68cb4ff8e"}, + {file = "coverage-7.10.6-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2b38261034fda87be356f2c3f42221fdb4171c3ce7658066ae449241485390d5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0e93b1476b79eae849dc3872faeb0bf7948fd9ea34869590bc16a2a00b9c82a7"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:ff8a991f70f4c0cf53088abf1e3886edcc87d53004c7bb94e78650b4d3dac3b5"}, + {file = "coverage-7.10.6-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ac765b026c9f33044419cbba1da913cfb82cca1b60598ac1c7a5ed6aac4621a0"}, + {file = "coverage-7.10.6-cp314-cp314t-win32.whl", hash = "sha256:441c357d55f4936875636ef2cfb3bee36e466dcf50df9afbd398ce79dba1ebb7"}, + {file = "coverage-7.10.6-cp314-cp314t-win_amd64.whl", hash = "sha256:073711de3181b2e204e4870ac83a7c4853115b42e9cd4d145f2231e12d670930"}, + {file = "coverage-7.10.6-cp314-cp314t-win_arm64.whl", hash = "sha256:137921f2bac5559334ba66122b753db6dc5d1cf01eb7b64eb412bb0d064ef35b"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:90558c35af64971d65fbd935c32010f9a2f52776103a259f1dee865fe8259352"}, + {file = "coverage-7.10.6-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:8953746d371e5695405806c46d705a3cd170b9cc2b9f93953ad838f6c1e58612"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c83f6afb480eae0313114297d29d7c295670a41c11b274e6bca0c64540c1ce7b"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7eb68d356ba0cc158ca535ce1381dbf2037fa8cb5b1ae5ddfc302e7317d04144"}, + {file = "coverage-7.10.6-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b15a87265e96307482746d86995f4bff282f14b027db75469c446da6127433b"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:fc53ba868875bfbb66ee447d64d6413c2db91fddcfca57025a0e7ab5b07d5862"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:efeda443000aa23f276f4df973cb82beca682fd800bb119d19e80504ffe53ec2"}, + {file = "coverage-7.10.6-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:9702b59d582ff1e184945d8b501ffdd08d2cee38d93a2206aa5f1365ce0b8d78"}, + {file = "coverage-7.10.6-cp39-cp39-win32.whl", hash = "sha256:2195f8e16ba1a44651ca684db2ea2b2d4b5345da12f07d9c22a395202a05b23c"}, + {file = "coverage-7.10.6-cp39-cp39-win_amd64.whl", hash = "sha256:f32ff80e7ef6a5b5b606ea69a36e97b219cd9dc799bcf2963018a4d8f788cfbf"}, + {file = "coverage-7.10.6-py3-none-any.whl", hash = "sha256:92c4ecf6bf11b2e85fd4d8204814dc26e6a19f0c9d938c207c5cb0eadfcabbe3"}, + {file = "coverage-7.10.6.tar.gz", hash = "sha256:f644a3ae5933a552a29dbb9aa2f90c677a875f80ebea028e5a52a4f429044b90"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] + +[[package]] +name = "crashtest" +version = "0.4.1" +description = "Manage Python errors with ease" +optional = true +python-versions = ">=3.7,<4.0" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "crashtest-0.4.1-py3-none-any.whl", hash = "sha256:8d23eac5fa660409f57472e3851dab7ac18aba459a8d19cbbba86d3d5aecd2a5"}, + {file = "crashtest-0.4.1.tar.gz", hash = "sha256:80d7b1f316ebfbd429f648076d6275c877ba30ba48979de4191714a75266f0ce"}, +] + +[[package]] +name = "cryptography" +version = "46.0.1" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.8" +groups = ["main", "build"] +files = [ + {file = "cryptography-46.0.1-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:1cd6d50c1a8b79af1a6f703709d8973845f677c8e97b1268f5ff323d38ce8475"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0ff483716be32690c14636e54a1f6e2e1b7bf8e22ca50b989f88fa1b2d287080"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9873bf7c1f2a6330bdfe8621e7ce64b725784f9f0c3a6a55c3047af5849f920e"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:0dfb7c88d4462a0cfdd0d87a3c245a7bc3feb59de101f6ff88194f740f72eda6"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e22801b61613ebdebf7deb18b507919e107547a1d39a3b57f5f855032dd7cfb8"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:757af4f6341ce7a1e47c326ca2a81f41d236070217e5fbbad61bbfe299d55d28"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:f7a24ea78de345cfa7f6a8d3bde8b242c7fac27f2bd78fa23474ca38dfaeeab9"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:9e8776dac9e660c22241b6587fae51a67b4b0147daa4d176b172c3ff768ad736"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9f40642a140c0c8649987027867242b801486865277cbabc8c6059ddef16dc8b"}, + {file = "cryptography-46.0.1-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:449ef2b321bec7d97ef2c944173275ebdab78f3abdd005400cc409e27cd159ab"}, + {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:2dd339ba3345b908fa3141ddba4025568fa6fd398eabce3ef72a29ac2d73ad75"}, + {file = "cryptography-46.0.1-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7411c910fb2a412053cf33cfad0153ee20d27e256c6c3f14d7d7d1d9fec59fd5"}, + {file = "cryptography-46.0.1-cp311-abi3-win32.whl", hash = "sha256:cbb8e769d4cac884bb28e3ff620ef1001b75588a5c83c9c9f1fdc9afbe7f29b0"}, + {file = "cryptography-46.0.1-cp311-abi3-win_amd64.whl", hash = "sha256:92e8cfe8bd7dd86eac0a677499894862cd5cc2fd74de917daa881d00871ac8e7"}, + {file = "cryptography-46.0.1-cp311-abi3-win_arm64.whl", hash = "sha256:db5597a4c7353b2e5fb05a8e6cb74b56a4658a2b7bf3cb6b1821ae7e7fd6eaa0"}, + {file = "cryptography-46.0.1-cp314-cp314t-macosx_10_9_universal2.whl", hash = "sha256:4c49eda9a23019e11d32a0eb51a27b3e7ddedde91e099c0ac6373e3aacc0d2ee"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9babb7818fdd71394e576cf26c5452df77a355eac1a27ddfa24096665a27f8fd"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9f2c4cc63be3ef43c0221861177cee5d14b505cd4d4599a89e2cd273c4d3542a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_aarch64.whl", hash = "sha256:41c281a74df173876da1dc9a9b6953d387f06e3d3ed9284e3baae3ab3f40883a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0a17377fa52563d730248ba1f68185461fff36e8bc75d8787a7dd2e20a802b7a"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_ppc64le.whl", hash = "sha256:0d1922d9280e08cde90b518a10cd66831f632960a8d08cb3418922d83fce6f12"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_28_x86_64.whl", hash = "sha256:af84e8e99f1a82cea149e253014ea9dc89f75b82c87bb6c7242203186f465129"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:ef648d2c690703501714588b2ba640facd50fd16548133b11b2859e8655a69da"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_ppc64le.whl", hash = "sha256:e94eb5fa32a8a9f9bf991f424f002913e3dd7c699ef552db9b14ba6a76a6313b"}, + {file = "cryptography-46.0.1-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:534b96c0831855e29fc3b069b085fd185aa5353033631a585d5cd4dd5d40d657"}, + {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:f9b55038b5c6c47559aa33626d8ecd092f354e23de3c6975e4bb205df128a2a0"}, + {file = "cryptography-46.0.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ec13b7105117dbc9afd023300fb9954d72ca855c274fe563e72428ece10191c0"}, + {file = "cryptography-46.0.1-cp314-cp314t-win32.whl", hash = "sha256:504e464944f2c003a0785b81668fe23c06f3b037e9cb9f68a7c672246319f277"}, + {file = "cryptography-46.0.1-cp314-cp314t-win_amd64.whl", hash = "sha256:c52fded6383f7e20eaf70a60aeddd796b3677c3ad2922c801be330db62778e05"}, + {file = "cryptography-46.0.1-cp314-cp314t-win_arm64.whl", hash = "sha256:9495d78f52c804b5ec8878b5b8c7873aa8e63db9cd9ee387ff2db3fffe4df784"}, + {file = "cryptography-46.0.1-cp38-abi3-macosx_10_9_universal2.whl", hash = "sha256:d84c40bdb8674c29fa192373498b6cb1e84f882889d21a471b45d1f868d8d44b"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9ed64e5083fa806709e74fc5ea067dfef9090e5b7a2320a49be3c9df3583a2d8"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:341fb7a26bc9d6093c1b124b9f13acc283d2d51da440b98b55ab3f79f2522ead"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:6ef1488967e729948d424d09c94753d0167ce59afba8d0f6c07a22b629c557b2"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7823bc7cdf0b747ecfb096d004cc41573c2f5c7e3a29861603a2871b43d3ef32"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_ppc64le.whl", hash = "sha256:f736ab8036796f5a119ff8211deda416f8c15ce03776db704a7a4e17381cb2ef"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:e46710a240a41d594953012213ea8ca398cd2448fbc5d0f1be8160b5511104a0"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:84ef1f145de5aee82ea2447224dc23f065ff4cc5791bb3b506615957a6ba8128"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_ppc64le.whl", hash = "sha256:9394c7d5a7565ac5f7d9ba38b2617448eba384d7b107b262d63890079fad77ca"}, + {file = "cryptography-46.0.1-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:ed957044e368ed295257ae3d212b95456bd9756df490e1ac4538857f67531fcc"}, + {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:f7de12fa0eee6234de9a9ce0ffcfa6ce97361db7a50b09b65c63ac58e5f22fc7"}, + {file = "cryptography-46.0.1-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:7fab1187b6c6b2f11a326f33b036f7168f5b996aedd0c059f9738915e4e8f53a"}, + {file = "cryptography-46.0.1-cp38-abi3-win32.whl", hash = "sha256:45f790934ac1018adeba46a0f7289b2b8fe76ba774a88c7f1922213a56c98bc1"}, + {file = "cryptography-46.0.1-cp38-abi3-win_amd64.whl", hash = "sha256:7176a5ab56fac98d706921f6416a05e5aff7df0e4b91516f450f8627cda22af3"}, + {file = "cryptography-46.0.1-cp38-abi3-win_arm64.whl", hash = "sha256:efc9e51c3e595267ff84adf56e9b357db89ab2279d7e375ffcaf8f678606f3d9"}, + {file = "cryptography-46.0.1-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd4b5e2ee4e60425711ec65c33add4e7a626adef79d66f62ba0acfd493af282d"}, + {file = "cryptography-46.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:48948940d0ae00483e85e9154bb42997d0b77c21e43a77b7773c8c80de532ac5"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:b9c79af2c3058430d911ff1a5b2b96bbfe8da47d5ed961639ce4681886614e70"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:0ca4be2af48c24df689a150d9cd37404f689e2968e247b6b8ff09bff5bcd786f"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:13e67c4d3fb8b6bc4ef778a7ccdd8df4cd15b4bcc18f4239c8440891a11245cc"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:15b5fd9358803b0d1cc42505a18d8bca81dabb35b5cfbfea1505092e13a9d96d"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e34da95e29daf8a71cb2841fd55df0511539a6cdf33e6f77c1e95e44006b9b46"}, + {file = "cryptography-46.0.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:34f04b7311174469ab3ac2647469743720f8b6c8b046f238e5cb27905695eb2a"}, + {file = "cryptography-46.0.1.tar.gz", hash = "sha256:ed570874e88f213437f5cf758f9ef26cbfc3f336d889b1e592ee11283bb8d1c7"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\""} + +[package.dependencies] +cffi = {version = ">=2.0.0", markers = "python_full_version >= \"3.9.0\" and platform_python_implementation != \"PyPy\""} +typing-extensions = {version = ">=4.13.2", markers = "python_full_version < \"3.11.0\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs", "sphinx-rtd-theme (>=3.0.0)"] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox[uv] (>=2024.4.15)"] +pep8test = ["check-sdist", "click (>=8.0.1)", "mypy (>=1.14)", "ruff (>=0.11.11)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==46.0.1)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "defusedxml" +version = "0.7.1" +description = "XML bomb protection for Python stdlib modules" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +groups = ["main"] +files = [ + {file = "defusedxml-0.7.1-py2.py3-none-any.whl", hash = "sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61"}, + {file = "defusedxml-0.7.1.tar.gz", hash = "sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69"}, +] + +[[package]] +name = "distlib" +version = "0.4.0" +description = "Distribution utilities" +optional = false +python-versions = "*" +groups = ["main", "test"] +files = [ + {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, + {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, +] + +[[package]] +name = "docutils" +version = "0.22" +description = "Docutils -- Python Documentation Utilities" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "docutils-0.22-py3-none-any.whl", hash = "sha256:4ed966a0e96a0477d852f7af31bdcb3adc049fbb35ccba358c2ea8a03287615e"}, + {file = "docutils-0.22.tar.gz", hash = "sha256:ba9d57750e92331ebe7c08a1bbf7a7f8143b86c476acd51528b042216a6aad0f"}, +] + +[[package]] +name = "dulwich" +version = "0.24.1" +description = "Python Git Library" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "dulwich-0.24.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2169c36b7955b40e1ec9b0543301a3dd536718c3b7840959ca70e7ed17397c25"}, + {file = "dulwich-0.24.1-cp310-cp310-manylinux_2_28_aarch64.whl", hash = "sha256:d16507ca6d6c2d29d7d942da4cc50fa589d58ab066030992dfa3932de6695062"}, + {file = "dulwich-0.24.1-cp310-cp310-manylinux_2_28_x86_64.whl", hash = "sha256:e893b800c72499e21d0160169bac574292626193532c336ffce7617fe02d97db"}, + {file = "dulwich-0.24.1-cp310-cp310-win32.whl", hash = "sha256:d7144febcad9e8510ed870a141073b07071390421691285a81cea5b9fa38d888"}, + {file = "dulwich-0.24.1-cp310-cp310-win_amd64.whl", hash = "sha256:1d8226ca444c4347e5820b4a0a3a8f91753c0e39e335eee1eaf59d9672356a9c"}, + {file = "dulwich-0.24.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:31ad6637322aaafeecc4c884f396ac2d963aadf201deb6422134fa0f8ac9a87a"}, + {file = "dulwich-0.24.1-cp311-cp311-manylinux_2_28_aarch64.whl", hash = "sha256:358e4b688f6c1fa5346a8394a2c1ab79ff7126be576b20ffd0f38085ead0df54"}, + {file = "dulwich-0.24.1-cp311-cp311-manylinux_2_28_x86_64.whl", hash = "sha256:50f981edd5307475f6f862ccdbe39e8dd01afc17f2ed8ee0e452c3878389b48c"}, + {file = "dulwich-0.24.1-cp311-cp311-win32.whl", hash = "sha256:741417a6a029a3230c46ad4725a50440cac852f165706824303d9939cf83770c"}, + {file = "dulwich-0.24.1-cp311-cp311-win_amd64.whl", hash = "sha256:816ec4abd152ebd11d05bf25b5d37a4a88c18af59857067ee85d32e43af12b5f"}, + {file = "dulwich-0.24.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6d227cebcb2082801ab429e196d973315dbe3818904b5c13a22d80a16f5692c9"}, + {file = "dulwich-0.24.1-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5e3c01b8109169aa361842af4987bca672087e3faf38d528ff9f631d1071f523"}, + {file = "dulwich-0.24.1-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:ee80d8e9199124974b486d2c83a7e2d4db17ae59682909fa198111d8bb416f50"}, + {file = "dulwich-0.24.1-cp312-cp312-win32.whl", hash = "sha256:bef4dccba44edd6d18015f67c9e0d6216f978840cdbe703930e1679e2872c595"}, + {file = "dulwich-0.24.1-cp312-cp312-win_amd64.whl", hash = "sha256:83b2fb17bac190cfc6c91e7a94a1d806aa8ce8903aca0e3e54cecb2c3f547a55"}, + {file = "dulwich-0.24.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:1a11ec69fc6604228804ddfc32c85b22bc627eca4cf4ff3f27dbe822e6f29477"}, + {file = "dulwich-0.24.1-cp313-cp313-manylinux_2_28_aarch64.whl", hash = "sha256:a9800df7238b586b4c38c00432776781bc889cf02d756dcfb8dc0ecb8fc47a33"}, + {file = "dulwich-0.24.1-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:3baab4a01aff890e2e6551ccbd33eb2a44173c897f0f027ad3aeab0fb057ec44"}, + {file = "dulwich-0.24.1-cp313-cp313-win32.whl", hash = "sha256:b39689aa4d143ba1fb0a687a4eb93d2e630d2c8f940aaa6c6911e9c8dca16e6a"}, + {file = "dulwich-0.24.1-cp313-cp313-win_amd64.whl", hash = "sha256:8fca9b863b939b52c5f759d292499f0d21a7bf7f8cbb9fdeb8cdd9511c5bc973"}, + {file = "dulwich-0.24.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:62e3ed32e48e2a7e37c5a97071beac43040cd700d0cab7867514a91335916c83"}, + {file = "dulwich-0.24.1-cp39-cp39-manylinux_2_28_aarch64.whl", hash = "sha256:6d87cc4770a69d547ebbbac535c83af8a5b762d9e5b1c886c40cb457a1b5c2c1"}, + {file = "dulwich-0.24.1-cp39-cp39-manylinux_2_28_x86_64.whl", hash = "sha256:10882685a8b03d0de321f277f6c8e6672bb849a378ad9823d482c42bb1ee8ee4"}, + {file = "dulwich-0.24.1-cp39-cp39-win32.whl", hash = "sha256:3df7ed03062e47f50675c83a7a1b73e48a95c9b413c2c8fca329b3e9f2700c04"}, + {file = "dulwich-0.24.1-cp39-cp39-win_amd64.whl", hash = "sha256:38000f553593e183189e06c6ed51377f106d28a2d98942d81eab9a10daef4663"}, + {file = "dulwich-0.24.1-py3-none-any.whl", hash = "sha256:57cc0dc5a21059698ffa4ed9a7272f1040ec48535193df84b0ee6b16bf615676"}, + {file = "dulwich-0.24.1.tar.gz", hash = "sha256:e19fd864f10f02bb834bb86167d92dcca1c228451b04458761fc13dabd447758"}, +] + +[package.dependencies] +typing_extensions = {version = ">=4.0", markers = "python_version < \"3.11\""} +urllib3 = ">=1.25" + +[package.extras] +colordiff = ["rich"] +dev = ["dissolve (>=0.1.1)", "mypy (==1.17.0)", "ruff (==0.12.4)"] +fastimport = ["fastimport"] +fuzzing = ["atheris"] +https = ["urllib3 (>=1.24.1)"] +merge = ["merge3"] +paramiko = ["paramiko"] +pgp = ["gpg"] + +[[package]] +name = "exceptiongroup" +version = "1.3.0" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +groups = ["main", "test"] +markers = "python_version == \"3.10\"" +files = [ + {file = "exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10"}, + {file = "exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88"}, +] + +[package.dependencies] +typing-extensions = {version = ">=4.6.0", markers = "python_version < \"3.13\""} + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "fastjsonschema" +version = "2.21.2" +description = "Fastest Python implementation of JSON schema" +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "fastjsonschema-2.21.2-py3-none-any.whl", hash = "sha256:1c797122d0a86c5cace2e54bf4e819c36223b552017172f32c5c024a6b77e463"}, + {file = "fastjsonschema-2.21.2.tar.gz", hash = "sha256:b1eb43748041c880796cd077f1a07c3d94e93ae84bba5ed36800a33554ae05de"}, +] + +[package.extras] +devel = ["colorama", "json-spec", "jsonschema", "pylint", "pytest", "pytest-benchmark", "pytest-cache", "validictory"] + +[[package]] +name = "filelock" +version = "3.19.1" +description = "A platform independent file lock." +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "filelock-3.19.1-py3-none-any.whl", hash = "sha256:d38e30481def20772f5baf097c122c3babc4fcdb7e14e57049eb9d88c6dc017d"}, + {file = "filelock-3.19.1.tar.gz", hash = "sha256:66eda1888b0171c998b35be2bcc0f6d75c388a7ce20c3f3f37aa8e96c2dddf58"}, +] + +[[package]] +name = "findpython" +version = "0.7.0" +description = "A utility to find python versions on your system" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "findpython-0.7.0-py3-none-any.whl", hash = "sha256:f53cfcc29536f5b83c962cf922bba8ff6d6a3c2a05fda6a45aa58a47d005d8fc"}, + {file = "findpython-0.7.0.tar.gz", hash = "sha256:8b31647c76352779a3c1a0806699b68e6a7bdc0b5c2ddd9af2a07a0d40c673dc"}, +] + +[package.dependencies] +packaging = ">=20" +platformdirs = ">=4.3.6" + +[[package]] +name = "h11" +version = "0.16.0" +description = "A pure-Python, bring-your-own-I/O implementation of HTTP/1.1" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86"}, + {file = "h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1"}, +] + +[[package]] +name = "httpcore" +version = "1.0.9" +description = "A minimal low-level HTTP client." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55"}, + {file = "httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8"}, +] + +[package.dependencies] +certifi = "*" +h11 = ">=0.16" + +[package.extras] +asyncio = ["anyio (>=4.0,<5.0)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +trio = ["trio (>=0.22.0,<1.0)"] + +[[package]] +name = "httpx" +version = "0.28.1" +description = "The next generation HTTP client." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad"}, + {file = "httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc"}, +] + +[package.dependencies] +anyio = "*" +certifi = "*" +httpcore = "==1.*" +idna = "*" + +[package.extras] +brotli = ["brotli ; platform_python_implementation == \"CPython\"", "brotlicffi ; platform_python_implementation != \"CPython\""] +cli = ["click (==8.*)", "pygments (==2.*)", "rich (>=10,<14)"] +http2 = ["h2 (>=3,<5)"] +socks = ["socksio (==1.*)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "id" +version = "1.5.0" +description = "A tool for generating OIDC identities" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, + {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, +] + +[package.dependencies] +requests = "*" + +[package.extras] +dev = ["build", "bump (>=1.3.2)", "id[lint,test]"] +lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"] +test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] + +[[package]] +name = "idna" +version = "3.10" +description = "Internationalized Domain Names in Applications (IDNA)" +optional = false +python-versions = ">=3.6" +groups = ["main", "build"] +files = [ + {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 = "importlib-metadata" +version = "8.7.0" +description = "Read metadata from Python packages" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version < \"3.12\""} + +[package.dependencies] +zipp = ">=3.20" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +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) ; python_version < \"3.9\"", "jaraco.test (>=5.4)", "packaging", "pyfakefs", "pytest (>=6,!=8.1.*)", "pytest-perf (>=0.9.2)"] +type = ["pytest-mypy"] + +[[package]] +name = "iniconfig" +version = "2.1.0" +description = "brain-dead simple config-ini parsing" +optional = false +python-versions = ">=3.8" +groups = ["main", "test"] +files = [ + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, +] + +[[package]] +name = "installer" +version = "0.7.0" +description = "A library for installing Python wheels." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "installer-0.7.0-py3-none-any.whl", hash = "sha256:05d1933f0a5ba7d8d6296bb6d5018e7c94fa473ceb10cf198a92ccea19c27b53"}, + {file = "installer-0.7.0.tar.gz", hash = "sha256:a26d3e3116289bb08216e0d0f7d925fcef0b0194eedfa0c944bcaaa106c4b631"}, +] + +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] +markers = {main = "extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] +markers = {main = "extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] + +[[package]] +name = "jaraco-functools" +version = "4.3.0" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8"}, + {file = "jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294"}, +] +markers = {main = "extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} + +[package.dependencies] +more_itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +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)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jeepney" +version = "0.9.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +groups = ["main", "build"] +files = [ + {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, + {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\""} + +[package.extras] +test = ["async-timeout ; python_version < \"3.11\"", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["trio"] + +[[package]] +name = "keyring" +version = "25.6.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, + {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, +] +markers = {main = "extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +completion = ["shtab (>=1.1.0)"] +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)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] + +[[package]] +name = "markdown-it-py" +version = "4.0.0" +description = "Python port of markdown-it. Markdown parsing, done right!" +optional = false +python-versions = ">=3.10" +groups = ["main", "bandit", "build"] +files = [ + {file = "markdown_it_py-4.0.0-py3-none-any.whl", hash = "sha256:87327c59b172c5011896038353a81343b6754500a08cd7a4973bb48c6d578147"}, + {file = "markdown_it_py-4.0.0.tar.gz", hash = "sha256:cb0a2b4aa34f932c007117b194e945bd74e0ec24133ceb5bac59009cda1cb9f3"}, +] + +[package.dependencies] +mdurl = ">=0.1,<1.0" + +[package.extras] +benchmarking = ["psutil", "pytest", "pytest-benchmark"] +compare = ["commonmark (>=0.9,<1.0)", "markdown (>=3.4,<4.0)", "markdown-it-pyrs", "mistletoe (>=1.0,<2.0)", "mistune (>=3.0,<4.0)", "panflute (>=2.3,<3.0)"] +linkify = ["linkify-it-py (>=1,<3)"] +plugins = ["mdit-py-plugins (>=0.5.0)"] +profiling = ["gprof2dot"] +rtd = ["ipykernel", "jupyter_sphinx", "mdit-py-plugins (>=0.5.0)", "myst-parser", "pyyaml", "sphinx", "sphinx-book-theme (>=1.0,<2.0)", "sphinx-copybutton", "sphinx-design"] +testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "requests"] + +[[package]] +name = "mdurl" +version = "0.1.2" +description = "Markdown URL utilities" +optional = false +python-versions = ">=3.7" +groups = ["main", "bandit", "build"] +files = [ + {file = "mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8"}, + {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, +] + +[[package]] +name = "more-itertools" +version = "10.8.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "more_itertools-10.8.0-py3-none-any.whl", hash = "sha256:52d4362373dcf7c52546bc4af9a86ee7c4579df9a8dc268be0a2f949d376cc9b"}, + {file = "more_itertools-10.8.0.tar.gz", hash = "sha256:f638ddf8a1a0d134181275fb5d58b086ead7c6a72429ad725c67503f13ba30bd"}, +] +markers = {main = "extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} + +[[package]] +name = "msgpack" +version = "1.1.1" +description = "MessagePack serializer" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "msgpack-1.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:353b6fc0c36fde68b661a12949d7d49f8f51ff5fa019c1e47c87c4ff34b080ed"}, + {file = "msgpack-1.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:79c408fcf76a958491b4e3b103d1c417044544b68e96d06432a189b43d1215c8"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:78426096939c2c7482bf31ef15ca219a9e24460289c00dd0b94411040bb73ad2"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8b17ba27727a36cb73aabacaa44b13090feb88a01d012c0f4be70c00f75048b4"}, + {file = "msgpack-1.1.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7a17ac1ea6ec3c7687d70201cfda3b1e8061466f28f686c24f627cae4ea8efd0"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:88d1e966c9235c1d4e2afac21ca83933ba59537e2e2727a999bf3f515ca2af26"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f6d58656842e1b2ddbe07f43f56b10a60f2ba5826164910968f5933e5178af75"}, + {file = "msgpack-1.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:96decdfc4adcbc087f5ea7ebdcfd3dee9a13358cae6e81d54be962efc38f6338"}, + {file = "msgpack-1.1.1-cp310-cp310-win32.whl", hash = "sha256:6640fd979ca9a212e4bcdf6eb74051ade2c690b862b679bfcb60ae46e6dc4bfd"}, + {file = "msgpack-1.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:8b65b53204fe1bd037c40c4148d00ef918eb2108d24c9aaa20bc31f9810ce0a8"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:71ef05c1726884e44f8b1d1773604ab5d4d17729d8491403a705e649116c9558"}, + {file = "msgpack-1.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:36043272c6aede309d29d56851f8841ba907a1a3d04435e43e8a19928e243c1d"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a32747b1b39c3ac27d0670122b57e6e57f28eefb725e0b625618d1b59bf9d1e0"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a8b10fdb84a43e50d38057b06901ec9da52baac6983d3f709d8507f3889d43f"}, + {file = "msgpack-1.1.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ba0c325c3f485dc54ec298d8b024e134acf07c10d494ffa24373bea729acf704"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:88daaf7d146e48ec71212ce21109b66e06a98e5e44dca47d853cbfe171d6c8d2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d8b55ea20dc59b181d3f47103f113e6f28a5e1c89fd5b67b9140edb442ab67f2"}, + {file = "msgpack-1.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a28e8072ae9779f20427af07f53bbb8b4aa81151054e882aee333b158da8752"}, + {file = "msgpack-1.1.1-cp311-cp311-win32.whl", hash = "sha256:7da8831f9a0fdb526621ba09a281fadc58ea12701bc709e7b8cbc362feabc295"}, + {file = "msgpack-1.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:5fd1b58e1431008a57247d6e7cc4faa41c3607e8e7d4aaf81f7c29ea013cb458"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:ae497b11f4c21558d95de9f64fff7053544f4d1a17731c866143ed6bb4591238"}, + {file = "msgpack-1.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:33be9ab121df9b6b461ff91baac6f2731f83d9b27ed948c5b9d1978ae28bf157"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6f64ae8fe7ffba251fecb8408540c34ee9df1c26674c50c4544d72dbf792e5ce"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a494554874691720ba5891c9b0b39474ba43ffb1aaf32a5dac874effb1619e1a"}, + {file = "msgpack-1.1.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cb643284ab0ed26f6957d969fe0dd8bb17beb567beb8998140b5e38a90974f6c"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d275a9e3c81b1093c060c3837e580c37f47c51eca031f7b5fb76f7b8470f5f9b"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4fd6b577e4541676e0cc9ddc1709d25014d3ad9a66caa19962c4f5de30fc09ef"}, + {file = "msgpack-1.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb29aaa613c0a1c40d1af111abf025f1732cab333f96f285d6a93b934738a68a"}, + {file = "msgpack-1.1.1-cp312-cp312-win32.whl", hash = "sha256:870b9a626280c86cff9c576ec0d9cbcc54a1e5ebda9cd26dab12baf41fee218c"}, + {file = "msgpack-1.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:5692095123007180dca3e788bb4c399cc26626da51629a31d40207cb262e67f4"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3765afa6bd4832fc11c3749be4ba4b69a0e8d7b728f78e68120a157a4c5d41f0"}, + {file = "msgpack-1.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:8ddb2bcfd1a8b9e431c8d6f4f7db0773084e107730ecf3472f1dfe9ad583f3d9"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:196a736f0526a03653d829d7d4c5500a97eea3648aebfd4b6743875f28aa2af8"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9d592d06e3cc2f537ceeeb23d38799c6ad83255289bb84c2e5792e5a8dea268a"}, + {file = "msgpack-1.1.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4df2311b0ce24f06ba253fda361f938dfecd7b961576f9be3f3fbd60e87130ac"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e4141c5a32b5e37905b5940aacbc59739f036930367d7acce7a64e4dec1f5e0b"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b1ce7f41670c5a69e1389420436f41385b1aa2504c3b0c30620764b15dded2e7"}, + {file = "msgpack-1.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4147151acabb9caed4e474c3344181e91ff7a388b888f1e19ea04f7e73dc7ad5"}, + {file = "msgpack-1.1.1-cp313-cp313-win32.whl", hash = "sha256:500e85823a27d6d9bba1d057c871b4210c1dd6fb01fbb764e37e4e8847376323"}, + {file = "msgpack-1.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:6d489fba546295983abd142812bda76b57e33d0b9f5d5b71c09a583285506f69"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bba1be28247e68994355e028dcd668316db30c1f758d3241a7b903ac78dcd285"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b8f93dcddb243159c9e4109c9750ba5b335ab8d48d9522c5308cd05d7e3ce600"}, + {file = "msgpack-1.1.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2fbbc0b906a24038c9958a1ba7ae0918ad35b06cb449d398b76a7d08470b0ed9"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:61e35a55a546a1690d9d09effaa436c25ae6130573b6ee9829c37ef0f18d5e78"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:1abfc6e949b352dadf4bce0eb78023212ec5ac42f6abfd469ce91d783c149c2a"}, + {file = "msgpack-1.1.1-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:996f2609ddf0142daba4cefd767d6db26958aac8439ee41db9cc0db9f4c4c3a6"}, + {file = "msgpack-1.1.1-cp38-cp38-win32.whl", hash = "sha256:4d3237b224b930d58e9d83c81c0dba7aacc20fcc2f89c1e5423aa0529a4cd142"}, + {file = "msgpack-1.1.1-cp38-cp38-win_amd64.whl", hash = "sha256:da8f41e602574ece93dbbda1fab24650d6bf2a24089f9e9dbb4f5730ec1e58ad"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f5be6b6bc52fad84d010cb45433720327ce886009d862f46b26d4d154001994b"}, + {file = "msgpack-1.1.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3a89cd8c087ea67e64844287ea52888239cbd2940884eafd2dcd25754fb72232"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d75f3807a9900a7d575d8d6674a3a47e9f227e8716256f35bc6f03fc597ffbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d182dac0221eb8faef2e6f44701812b467c02674a322c739355c39e94730cdbf"}, + {file = "msgpack-1.1.1-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1b13fe0fb4aac1aa5320cd693b297fe6fdef0e7bea5518cbc2dd5299f873ae90"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:435807eeb1bc791ceb3247d13c79868deb22184e1fc4224808750f0d7d1affc1"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:4835d17af722609a45e16037bb1d4d78b7bdf19d6c0128116d178956618c4e88"}, + {file = "msgpack-1.1.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a8ef6e342c137888ebbfb233e02b8fbd689bb5b5fcc59b34711ac47ebd504478"}, + {file = "msgpack-1.1.1-cp39-cp39-win32.whl", hash = "sha256:61abccf9de335d9efd149e2fff97ed5974f2481b3353772e8e2dd3402ba2bd57"}, + {file = "msgpack-1.1.1-cp39-cp39-win_amd64.whl", hash = "sha256:40eae974c873b2992fd36424a5d9407f93e97656d999f43fca9d29f820899084"}, + {file = "msgpack-1.1.1.tar.gz", hash = "sha256:77b79ce34a2bdab2594f490c8e80dd62a02d650b91a75159a63ec413b8d104cd"}, +] + +[[package]] +name = "mypy" +version = "1.18.1" +description = "Optional static typing for Python" +optional = false +python-versions = ">=3.9" +groups = ["main", "type"] +files = [ + {file = "mypy-1.18.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2761b6ae22a2b7d8e8607fb9b81ae90bc2e95ec033fd18fa35e807af6c657763"}, + {file = "mypy-1.18.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b10e3ea7f2eec23b4929a3fabf84505da21034a4f4b9613cda81217e92b74f3"}, + {file = "mypy-1.18.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:261fbfced030228bc0f724d5d92f9ae69f46373bdfd0e04a533852677a11dbea"}, + {file = "mypy-1.18.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4dc6b34a1c6875e6286e27d836a35c0d04e8316beac4482d42cfea7ed2527df8"}, + {file = "mypy-1.18.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1cabb353194d2942522546501c0ff75c4043bf3b63069cb43274491b44b773c9"}, + {file = "mypy-1.18.1-cp310-cp310-win_amd64.whl", hash = "sha256:738b171690c8e47c93569635ee8ec633d2cdb06062f510b853b5f233020569a9"}, + {file = "mypy-1.18.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6c903857b3e28fc5489e54042684a9509039ea0aedb2a619469438b544ae1961"}, + {file = "mypy-1.18.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2a0c8392c19934c2b6c65566d3a6abdc6b51d5da7f5d04e43f0eb627d6eeee65"}, + {file = "mypy-1.18.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f85eb7efa2ec73ef63fc23b8af89c2fe5bf2a4ad985ed2d3ff28c1bb3c317c92"}, + {file = "mypy-1.18.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:82ace21edf7ba8af31c3308a61dc72df30500f4dbb26f99ac36b4b80809d7e94"}, + {file = "mypy-1.18.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:a2dfd53dfe632f1ef5d161150a4b1f2d0786746ae02950eb3ac108964ee2975a"}, + {file = "mypy-1.18.1-cp311-cp311-win_amd64.whl", hash = "sha256:320f0ad4205eefcb0e1a72428dde0ad10be73da9f92e793c36228e8ebf7298c0"}, + {file = "mypy-1.18.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:502cde8896be8e638588b90fdcb4c5d5b8c1b004dfc63fd5604a973547367bb9"}, + {file = "mypy-1.18.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7509549b5e41be279afc1228242d0e397f1af2919a8f2877ad542b199dc4083e"}, + {file = "mypy-1.18.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5956ecaabb3a245e3f34100172abca1507be687377fe20e24d6a7557e07080e2"}, + {file = "mypy-1.18.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8750ceb014a96c9890421c83f0db53b0f3b8633e2864c6f9bc0a8e93951ed18d"}, + {file = "mypy-1.18.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fb89ea08ff41adf59476b235293679a6eb53a7b9400f6256272fb6029bec3ce5"}, + {file = "mypy-1.18.1-cp312-cp312-win_amd64.whl", hash = "sha256:2657654d82fcd2a87e02a33e0d23001789a554059bbf34702d623dafe353eabf"}, + {file = "mypy-1.18.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d70d2b5baf9b9a20bc9c730015615ae3243ef47fb4a58ad7b31c3e0a59b5ef1f"}, + {file = "mypy-1.18.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:b8367e33506300f07a43012fc546402f283c3f8bcff1dc338636affb710154ce"}, + {file = "mypy-1.18.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:913f668ec50c3337b89df22f973c1c8f0b29ee9e290a8b7fe01cc1ef7446d42e"}, + {file = "mypy-1.18.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1a0e70b87eb27b33209fa4792b051c6947976f6ab829daa83819df5f58330c71"}, + {file = "mypy-1.18.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c378d946e8a60be6b6ede48c878d145546fb42aad61df998c056ec151bf6c746"}, + {file = "mypy-1.18.1-cp313-cp313-win_amd64.whl", hash = "sha256:2cd2c1e0f3a7465f22731987fff6fc427e3dcbb4ca5f7db5bbeaff2ff9a31f6d"}, + {file = "mypy-1.18.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:ba24603c58e34dd5b096dfad792d87b304fc6470cbb1c22fd64e7ebd17edcc61"}, + {file = "mypy-1.18.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ed36662fb92ae4cb3cacc682ec6656208f323bbc23d4b08d091eecfc0863d4b5"}, + {file = "mypy-1.18.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:040ecc95e026f71a9ad7956fea2724466602b561e6a25c2e5584160d3833aaa8"}, + {file = "mypy-1.18.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:937e3ed86cb731276706e46e03512547e43c391a13f363e08d0fee49a7c38a0d"}, + {file = "mypy-1.18.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:1f95cc4f01c0f1701ca3b0355792bccec13ecb2ec1c469e5b85a6ef398398b1d"}, + {file = "mypy-1.18.1-cp314-cp314-win_amd64.whl", hash = "sha256:e4f16c0019d48941220ac60b893615be2f63afedaba6a0801bdcd041b96991ce"}, + {file = "mypy-1.18.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e37763af63a8018308859bc83d9063c501a5820ec5bd4a19f0a2ac0d1c25c061"}, + {file = "mypy-1.18.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:51531b6e94f34b8bd8b01dee52bbcee80daeac45e69ec5c36e25bce51cbc46e6"}, + {file = "mypy-1.18.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dbfdea20e90e9c5476cea80cfd264d8e197c6ef2c58483931db2eefb2f7adc14"}, + {file = "mypy-1.18.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:99f272c9b59f5826fffa439575716276d19cbf9654abc84a2ba2d77090a0ba14"}, + {file = "mypy-1.18.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:8c05a7f8c00300a52f3a4fcc95a185e99bf944d7e851ff141bae8dcf6dcfeac4"}, + {file = "mypy-1.18.1-cp39-cp39-win_amd64.whl", hash = "sha256:2fbcecbe5cf213ba294aa8c0b8c104400bf7bb64db82fb34fe32a205da4b3531"}, + {file = "mypy-1.18.1-py3-none-any.whl", hash = "sha256:b76a4de66a0ac01da1be14ecc8ae88ddea33b8380284a9e3eae39d57ebcbe26e"}, + {file = "mypy-1.18.1.tar.gz", hash = "sha256:9e988c64ad3ac5987f43f5154f884747faf62141b7f842e87465b45299eea5a9"}, +] + +[package.dependencies] +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" +tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} +typing_extensions = ">=4.6.0" + +[package.extras] +dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] +install-types = ["pip"] +mypyc = ["setuptools (>=50)"] +reports = ["lxml"] + +[[package]] +name = "mypy-extensions" +version = "1.1.0" +description = "Type system extensions for programs checked with the mypy type checker." +optional = false +python-versions = ">=3.8" +groups = ["main", "type"] +files = [ + {file = "mypy_extensions-1.1.0-py3-none-any.whl", hash = "sha256:1be4cccdb0f2482337c4743e60421de3a356cd97508abadd57d47403e94f5505"}, + {file = "mypy_extensions-1.1.0.tar.gz", hash = "sha256:52e68efc3284861e772bbcd66823fde5ae21fd2fdb51c62a211403730b916558"}, +] + +[[package]] +name = "nh3" +version = "0.3.0" +description = "Python binding to Ammonia HTML sanitizer Rust crate" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "nh3-0.3.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a537ece1bf513e5a88d8cff8a872e12fe8d0f42ef71dd15a5e7520fecd191bbb"}, + {file = "nh3-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c915060a2c8131bef6a29f78debc29ba40859b6dbe2362ef9e5fd44f11487c2"}, + {file = "nh3-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba0caa8aa184196daa6e574d997a33867d6d10234018012d35f86d46024a2a95"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80fe20171c6da69c7978ecba33b638e951b85fb92059259edd285ff108b82a6d"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e90883f9f85288f423c77b3f5a6f4486375636f25f793165112679a7b6363b35"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0649464ac8eee018644aacbc103874ccbfac80e3035643c3acaab4287e36e7f5"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1adeb1062a1c2974bc75b8d1ecb014c5fd4daf2df646bbe2831f7c23659793f9"}, + {file = "nh3-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:7275fdffaab10cc5801bf026e3c089d8de40a997afc9e41b981f7ac48c5aa7d5"}, + {file = "nh3-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:423201bbdf3164a9e09aa01e540adbb94c9962cc177d5b1cbb385f5e1e79216e"}, + {file = "nh3-0.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:16f8670201f7e8e0e05ed1a590eb84bfa51b01a69dd5caf1d3ea57733de6a52f"}, + {file = "nh3-0.3.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ec6cfdd2e0399cb79ba4dcffb2332b94d9696c52272ff9d48a630c5dca5e325a"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5e7185599f89b0e391e2f29cc12dc2e206167380cea49b33beda4891be2fe1"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:389d93d59b8214d51c400fb5b07866c2a4f79e4e14b071ad66c92184fec3a392"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e9e6a7e4d38f7e8dda9edd1433af5170c597336c1a74b4693c5cb75ab2b30f2a"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7852f038a054e0096dac12b8141191e02e93e0b4608c4b993ec7d4ffafea4e49"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af5aa8127f62bbf03d68f67a956627b1bd0469703a35b3dad28d0c1195e6c7fb"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f416c35efee3e6a6c9ab7716d9e57aa0a49981be915963a82697952cba1353e1"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37d3003d98dedca6cd762bf88f2e70b67f05100f6b949ffe540e189cc06887f9"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:634e34e6162e0408e14fb61d5e69dbaea32f59e847cfcfa41b66100a6b796f62"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:b0612ccf5de8a480cf08f047b08f9d3fecc12e63d2ee91769cb19d7290614c23"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c7a32a7f0d89f7d30cb8f4a84bdbd56d1eb88b78a2434534f62c71dac538c450"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3f1b4f8a264a0c86ea01da0d0c390fe295ea0bcacc52c2103aca286f6884f518"}, + {file = "nh3-0.3.0-cp38-abi3-win32.whl", hash = "sha256:6d68fa277b4a3cf04e5c4b84dd0c6149ff7d56c12b3e3fab304c525b850f613d"}, + {file = "nh3-0.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:bae63772408fd63ad836ec569a7c8f444dd32863d0c67f6e0b25ebbd606afa95"}, + {file = "nh3-0.3.0-cp38-abi3-win_arm64.whl", hash = "sha256:d97d3efd61404af7e5721a0e74d81cdbfc6e5f97e11e731bb6d090e30a7b62b2"}, + {file = "nh3-0.3.0.tar.gz", hash = "sha256:d8ba24cb31525492ea71b6aac11a4adac91d828aadeff7c4586541bf5dc34d2f"}, +] + +[[package]] +name = "packaging" +version = "25.0" +description = "Core utilities for Python packages" +optional = false +python-versions = ">=3.8" +groups = ["main", "build", "test"] +files = [ + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, +] + +[[package]] +name = "pathspec" +version = "0.12.1" +description = "Utility library for gitignore style pattern matching of file paths." +optional = false +python-versions = ">=3.8" +groups = ["main", "type"] +files = [ + {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, + {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, +] + +[[package]] +name = "pbs-installer" +version = "2025.9.18" +description = "Installer for Python Build Standalone" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "pbs_installer-2025.9.18-py3-none-any.whl", hash = "sha256:8ef55d7675698747505c237015d14c81759bd66a0d4c8b20cec9a2dc96e8434c"}, + {file = "pbs_installer-2025.9.18.tar.gz", hash = "sha256:c0a51a7c1e015723bd8396f02e15b5876e439f74b0f45bbac436b189f903219f"}, +] + +[package.dependencies] +httpx = {version = ">=0.27.0,<1", optional = true, markers = "extra == \"download\""} +zstandard = {version = ">=0.21.0", optional = true, markers = "extra == \"install\""} + +[package.extras] +all = ["pbs-installer[download,install]"] +download = ["httpx (>=0.27.0,<1)"] +install = ["zstandard (>=0.21.0)"] + +[[package]] +name = "pkginfo" +version = "1.12.1.2" +description = "Query metadata from sdists / bdists / installed packages." +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "pkginfo-1.12.1.2-py3-none-any.whl", hash = "sha256:c783ac885519cab2c34927ccfa6bf64b5a704d7c69afaea583dd9b7afe969343"}, + {file = "pkginfo-1.12.1.2.tar.gz", hash = "sha256:5cd957824ac36f140260964eba3c6be6442a8359b8c48f4adf90210f33a04b7b"}, +] + +[package.extras] +testing = ["pytest", "pytest-cov", "wheel"] + +[[package]] +name = "platformdirs" +version = "4.4.0" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "platformdirs-4.4.0-py3-none-any.whl", hash = "sha256:abd01743f24e5287cd7a5db3752faf1a2d65353f38ec26d98e25a6db65958c85"}, + {file = "platformdirs-4.4.0.tar.gz", hash = "sha256:ca753cf4d81dc309bc67b0ea38fd15dc97bc30ce419a7f58d13eb3bf14c4febf"}, +] + +[package.extras] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.4)", "pytest-cov (>=6)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.14.1)"] + +[[package]] +name = "pluggy" +version = "1.6.0" +description = "plugin and hook calling mechanisms for python" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["coverage", "pytest", "pytest-benchmark"] + +[[package]] +name = "poetry" +version = "2.2.1" +description = "Python dependency management and packaging made easy." +optional = true +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "poetry-2.2.1-py3-none-any.whl", hash = "sha256:f5958b908b96c5824e2acbb8b19cdef8a3351c62142d7ecff2d705396c8ca34c"}, + {file = "poetry-2.2.1.tar.gz", hash = "sha256:bef9aa4bb00ce4c10b28b25e7bac724094802d6958190762c45df6c12749b37c"}, +] + +[package.dependencies] +build = ">=1.2.1,<2.0.0" +cachecontrol = {version = ">=0.14.0,<0.15.0", extras = ["filecache"]} +cleo = ">=2.1.0,<3.0.0" +dulwich = ">=0.24.0,<0.25.0" +fastjsonschema = ">=2.18.0,<3.0.0" +findpython = ">=0.6.2,<0.8.0" +installer = ">=0.7.0,<0.8.0" +keyring = ">=25.1.0,<26.0.0" +packaging = ">=24.2" +pbs-installer = {version = ">=2025.1.6,<2026.0.0", extras = ["download", "install"]} +pkginfo = ">=1.12,<2.0" +platformdirs = ">=3.0.0,<5" +poetry-core = "2.2.1" +pyproject-hooks = ">=1.0.0,<2.0.0" +requests = ">=2.26,<3.0" +requests-toolbelt = ">=1.0.0,<2.0.0" +shellingham = ">=1.5,<2.0" +tomli = {version = ">=2.0.1,<3.0.0", markers = "python_version < \"3.11\""} +tomlkit = ">=0.11.4,<1.0.0" +trove-classifiers = ">=2022.5.19" +virtualenv = ">=20.26.6" +xattr = {version = ">=1.0.0,<2.0.0", markers = "sys_platform == \"darwin\""} + +[[package]] +name = "poetry-core" +version = "2.2.1" +description = "Poetry PEP 517 Build Backend" +optional = true +python-versions = "<4.0,>=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "poetry_core-2.2.1-py3-none-any.whl", hash = "sha256:bdfce710edc10bfcf9ab35041605c480829be4ab23f5bc01202cfe5db8f125ab"}, + {file = "poetry_core-2.2.1.tar.gz", hash = "sha256:97e50d8593c8729d3f49364b428583e044087ee3def1e010c6496db76bd65ac5"}, +] + +[[package]] +name = "pycparser" +version = "2.23" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "build"] +files = [ + {file = "pycparser-2.23-py3-none-any.whl", hash = "sha256:e5c6e8d3fbad53479cab09ac03729e0a9faf2bee3db8208a550daf5af81a5934"}, + {file = "pycparser-2.23.tar.gz", hash = "sha256:78816d4f24add8f10a06d6f05b4d424ad9e96cfebf68a4ddc99c65c0720d00c2"}, +] +markers = {main = "((extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" or extra == \"build\" and sys_platform == \"darwin\") and implementation_name != \"PyPy\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\" and implementation_name != \"PyPy\""} + +[[package]] +name = "pydantic" +version = "2.11.9" +description = "Data validation using Python type hints" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic-2.11.9-py3-none-any.whl", hash = "sha256:c42dd626f5cfc1c6950ce6205ea58c93efa406da65f479dcb4029d5934857da2"}, + {file = "pydantic-2.11.9.tar.gz", hash = "sha256:6b8ffda597a14812a7975c90b82a8a2e777d9257aba3453f973acd3c032a18e2"}, +] + +[package.dependencies] +annotated-types = ">=0.6.0" +pydantic-core = "2.33.2" +typing-extensions = ">=4.12.2" +typing-inspection = ">=0.4.0" + +[package.extras] +email = ["email-validator (>=2.0.0)"] +timezone = ["tzdata ; python_version >= \"3.9\" and platform_system == \"Windows\""] + +[[package]] +name = "pydantic-core" +version = "2.33.2" +description = "Core functionality for Pydantic validation and serialization" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8"}, + {file = "pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2"}, + {file = "pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a"}, + {file = "pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22"}, + {file = "pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7"}, + {file = "pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef"}, + {file = "pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30"}, + {file = "pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab"}, + {file = "pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc"}, + {file = "pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6"}, + {file = "pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2"}, + {file = "pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f"}, + {file = "pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d"}, + {file = "pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e"}, + {file = "pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9"}, + {file = "pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5"}, + {file = "pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:a2b911a5b90e0374d03813674bf0a5fbbb7741570dcd4b4e85a2e48d17def29d"}, + {file = "pydantic_core-2.33.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:6fa6dfc3e4d1f734a34710f391ae822e0a8eb8559a85c6979e14e65ee6ba2954"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c54c939ee22dc8e2d545da79fc5381f1c020d6d3141d3bd747eab59164dc89fb"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:53a57d2ed685940a504248187d5685e49eb5eef0f696853647bf37c418c538f7"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:09fb9dd6571aacd023fe6aaca316bd01cf60ab27240d7eb39ebd66a3a15293b4"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0e6116757f7959a712db11f3e9c0a99ade00a5bbedae83cb801985aa154f071b"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d55ab81c57b8ff8548c3e4947f119551253f4e3787a7bbc0b6b3ca47498a9d3"}, + {file = "pydantic_core-2.33.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:c20c462aa4434b33a2661701b861604913f912254e441ab8d78d30485736115a"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:44857c3227d3fb5e753d5fe4a3420d6376fa594b07b621e220cd93703fe21782"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_armv7l.whl", hash = "sha256:eb9b459ca4df0e5c87deb59d37377461a538852765293f9e6ee834f0435a93b9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:9fcd347d2cc5c23b06de6d3b7b8275be558a0c90549495c699e379a80bf8379e"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win32.whl", hash = "sha256:83aa99b1285bc8f038941ddf598501a86f1536789740991d7d8756e34f1e74d9"}, + {file = "pydantic_core-2.33.2-cp39-cp39-win_amd64.whl", hash = "sha256:f481959862f57f29601ccced557cc2e817bce7533ab8e01a797a48b49c9692b3"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c"}, + {file = "pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb"}, + {file = "pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:87acbfcf8e90ca885206e98359d7dca4bcbb35abdc0ff66672a293e1d7a19101"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:7f92c15cd1e97d4b12acd1cc9004fa092578acfa57b67ad5e43a197175d01a64"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3f26877a748dc4251cfcfda9dfb5f13fcb034f5308388066bcfe9031b63ae7d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dac89aea9af8cd672fa7b510e7b8c33b0bba9a43186680550ccf23020f32d535"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:970919794d126ba8645f3837ab6046fb4e72bbc057b3709144066204c19a455d"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:3eb3fe62804e8f859c49ed20a8451342de53ed764150cb14ca71357c765dc2a6"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:3abcd9392a36025e3bd55f9bd38d908bd17962cc49bc6da8e7e96285336e2bca"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:3a1c81334778f9e3af2f8aeb7a960736e5cab1dfebfb26aabca09afd2906c039"}, + {file = "pydantic_core-2.33.2-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2807668ba86cb38c6817ad9bc66215ab8584d1d304030ce4f0887336f28a5e27"}, + {file = "pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc"}, +] + +[package.dependencies] +typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" + +[[package]] +name = "pygments" +version = "2.19.2" +description = "Pygments is a syntax highlighting package written in Python." +optional = false +python-versions = ">=3.8" +groups = ["main", "bandit", "build", "test"] +files = [ + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, +] + +[package.extras] +windows-terminal = ["colorama (>=0.4.6)"] + +[[package]] +name = "pyproject-api" +version = "1.9.1" +description = "API to interact with the python pyproject.toml based projects" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "pyproject_api-1.9.1-py3-none-any.whl", hash = "sha256:7d6238d92f8962773dd75b5f0c4a6a27cce092a14b623b811dba656f3b628948"}, + {file = "pyproject_api-1.9.1.tar.gz", hash = "sha256:43c9918f49daab37e302038fc1aed54a8c7a91a9fa935d00b9a485f37e0f5335"}, +] + +[package.dependencies] +packaging = ">=25" +tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2024.8.6)", "sphinx-autodoc-typehints (>=3.2)"] +testing = ["covdefaults (>=2.3)", "pytest (>=8.3.5)", "pytest-cov (>=6.1.1)", "pytest-mock (>=3.14)", "setuptools (>=80.3.1)"] + +[[package]] +name = "pyproject-hooks" +version = "1.2.0" +description = "Wrappers to call pyproject.toml-based build backend hooks." +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "pyproject_hooks-1.2.0-py3-none-any.whl", hash = "sha256:9e5c6bfa8dcc30091c74b0cf803c81fdd29d94f01992a7707bc97babb1141913"}, + {file = "pyproject_hooks-1.2.0.tar.gz", hash = "sha256:1e859bd5c40fae9448642dd871adf459e5e2084186e8d2c2a79a824c970da1f8"}, +] + +[[package]] +name = "pytest" +version = "8.4.2" +description = "pytest: simple powerful testing with Python" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "pytest-8.4.2-py3-none-any.whl", hash = "sha256:872f880de3fc3a5bdc88a11b39c9710c3497a547cfa9320bc3c5e62fbf272e79"}, + {file = "pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01"}, +] + +[package.dependencies] +colorama = {version = ">=0.4", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1", markers = "python_version < \"3.11\""} +iniconfig = ">=1" +packaging = ">=20" +pluggy = ">=1.5,<2" +pygments = ">=2.7.2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} + +[package.extras] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "requests", "setuptools", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "7.0.0" +description = "Pytest plugin for measuring coverage." +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "pytest_cov-7.0.0-py3-none-any.whl", hash = "sha256:3b8e9558b16cc1479da72058bdecf8073661c7f57f7d3c5f22a1c23507f2d861"}, + {file = "pytest_cov-7.0.0.tar.gz", hash = "sha256:33c97eda2e049a0c5298e91f519302a1334c26ac65c1a483d6206fd458361af1"}, +] + +[package.dependencies] +coverage = {version = ">=7.10.6", extras = ["toml"]} +pluggy = ">=1.2" +pytest = ">=7" + +[package.extras] +testing = ["process-tests", "pytest-xdist", "virtualenv"] + +[[package]] +name = "pytest-env" +version = "1.1.5" +description = "pytest plugin that allows you to add environment variables." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"test\"" +files = [ + {file = "pytest_env-1.1.5-py3-none-any.whl", hash = "sha256:ce90cf8772878515c24b31cd97c7fa1f4481cd68d588419fd45f10ecaee6bc30"}, + {file = "pytest_env-1.1.5.tar.gz", hash = "sha256:91209840aa0e43385073ac464a554ad2947cc2fd663a9debf88d03b01e0cc1cf"}, +] + +[package.dependencies] +pytest = ">=8.3.3" +tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "pytest-mock (>=3.14)"] + +[[package]] +name = "pytest-mock" +version = "3.15.1" +description = "Thin-wrapper around the mock package for easier use with pytest" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "pytest_mock-3.15.1-py3-none-any.whl", hash = "sha256:0a25e2eb88fe5168d535041d09a4529a188176ae608a6d249ee65abc0949630d"}, + {file = "pytest_mock-3.15.1.tar.gz", hash = "sha256:1849a238f6f396da19762269de72cb1814ab44416fa73a8686deac10b0d87a0f"}, +] + +[package.dependencies] +pytest = ">=6.2.5" + +[package.extras] +dev = ["pre-commit", "pytest-asyncio", "tox"] + +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +groups = ["main", "build"] +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"win32\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"win32\""} + +[[package]] +name = "pyyaml" +version = "6.0.2" +description = "YAML parser and emitter for Python" +optional = false +python-versions = ">=3.8" +groups = ["main", "bandit"] +files = [ + {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 = "rapidfuzz" +version = "3.14.1" +description = "rapid fuzzy string matching" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "rapidfuzz-3.14.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:489440e4b5eea0d150a31076eb183bed0ec84f934df206c72ae4fc3424501758"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:eff22cc938c3f74d194df03790a6c3325d213b28cf65cdefd6fdeae759b745d5"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e0307f018b16feaa36074bcec2496f6f120af151a098910296e72e233232a62f"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bc133652da143aca1ab72de235446432888b2b7f44ee332d006f8207967ecb8a"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e9e71b3fe7e4a1590843389a90fe2a8684649fc74b9b7446e17ee504ddddb7de"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c51519eb2f20b52eba6fc7d857ae94acc6c2a1f5d0f2d794b9d4977cdc29dd7"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:fe87d94602624f8f25fff9a0a7b47f33756c4d9fc32b6d3308bb142aa483b8a4"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:2d665380503a575dda52eb712ea521f789e8f8fd629c7a8e6c0f8ff480febc78"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:c0f0dd022b8a7cbf3c891f6de96a80ab6a426f1069a085327816cea749e096c2"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf1ba22d36858b265c95cd774ba7fe8991e80a99cd86fe4f388605b01aee81a3"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:ca1c1494ac9f9386d37f0e50cbaf4d07d184903aed7691549df1b37e9616edc9"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9e4b12e921b0fa90d7c2248742a536f21eae5562174090b83edd0b4ab8b557d7"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-win32.whl", hash = "sha256:5e1c1f2292baa4049535b07e9e81feb29e3650d2ba35ee491e64aca7ae4cb15e"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-win_amd64.whl", hash = "sha256:59a8694beb9a13c4090ab3d1712cabbd896c6949706d1364e2a2e1713c413760"}, + {file = "rapidfuzz-3.14.1-cp310-cp310-win_arm64.whl", hash = "sha256:e94cee93faa792572c574a615abe12912124b4ffcf55876b72312914ab663345"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4d976701060886a791c8a9260b1d4139d14c1f1e9a6ab6116b45a1acf3baff67"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5e6ba7e6eb2ab03870dcab441d707513db0b4264c12fba7b703e90e8b4296df2"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1e532bf46de5fd3a1efde73a16a4d231d011bce401c72abe3c6ecf9de681003f"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:f9b6a6fb8ed9b951e5f3b82c1ce6b1665308ec1a0da87f799b16e24fc59e4662"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:5b6ac3f9810949caef0e63380b11a3c32a92f26bacb9ced5e32c33560fcdf8d1"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e52e4c34fd567f77513e886b66029c1ae02f094380d10eba18ba1c68a46d8b90"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:2ef72e41b1a110149f25b14637f1cedea6df192462120bea3433980fe9d8ac05"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fb654a35b373d712a6b0aa2a496b2b5cdd9d32410cfbaecc402d7424a90ba72a"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:2b2c12e5b9eb8fe9a51b92fe69e9ca362c0970e960268188a6d295e1dec91e6d"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4f069dec5c450bd987481e752f0a9979e8fdf8e21e5307f5058f5c4bb162fa56"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:4d0d9163725b7ad37a8c46988cae9ebab255984db95ad01bf1987ceb9e3058dd"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:db656884b20b213d846f6bc990c053d1f4a60e6d4357f7211775b02092784ca1"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-win32.whl", hash = "sha256:4b42f7b9c58cbcfbfaddc5a6278b4ca3b6cd8983e7fd6af70ca791dff7105fb9"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-win_amd64.whl", hash = "sha256:e5847f30d7d4edefe0cb37294d956d3495dd127c1c56e9128af3c2258a520bb4"}, + {file = "rapidfuzz-3.14.1-cp311-cp311-win_arm64.whl", hash = "sha256:5087d8ad453092d80c042a08919b1cb20c8ad6047d772dc9312acd834da00f75"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:809515194f628004aac1b1b280c3734c5ea0ccbd45938c9c9656a23ae8b8f553"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0afcf2d6cb633d0d4260d8df6a40de2d9c93e9546e2c6b317ab03f89aa120ad7"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5c1c3d07d53dcafee10599da8988d2b1f39df236aee501ecbd617bd883454fcd"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e9ee3e1eb0a027717ee72fe34dc9ac5b3e58119f1bd8dd15bc19ed54ae3e62b"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:70c845b64a033a20c44ed26bc890eeb851215148cc3e696499f5f65529afb6cb"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26db0e815213d04234298dea0d884d92b9cb8d4ba954cab7cf67a35853128a33"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:6ad3395a416f8b126ff11c788531f157c7debeb626f9d897c153ff8980da10fb"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:61c5b9ab6f730e6478aa2def566223712d121c6f69a94c7cc002044799442afd"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13e0ea3d0c533969158727d1bb7a08c2cc9a816ab83f8f0dcfde7e38938ce3e6"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6325ca435b99f4001aac919ab8922ac464999b100173317defb83eae34e82139"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:07a9fad3247e68798424bdc116c1094e88ecfabc17b29edf42a777520347648e"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f8ff5dbe78db0a10c1f916368e21d328935896240f71f721e073cf6c4c8cdedd"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-win32.whl", hash = "sha256:9c83270e44a6ae7a39fc1d7e72a27486bccc1fa5f34e01572b1b90b019e6b566"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-win_amd64.whl", hash = "sha256:e06664c7fdb51c708e082df08a6888fce4c5c416d7e3cc2fa66dd80eb76a149d"}, + {file = "rapidfuzz-3.14.1-cp312-cp312-win_arm64.whl", hash = "sha256:6c7c26025f7934a169a23dafea6807cfc3fb556f1dd49229faf2171e5d8101cc"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8d69f470d63ee824132ecd80b1974e1d15dd9df5193916901d7860cef081a260"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:6f571d20152fc4833b7b5e781b36d5e4f31f3b5a596a3d53cf66a1bd4436b4f4"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:61d77e09b2b6bc38228f53b9ea7972a00722a14a6048be9a3672fb5cb08bad3a"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b41d95ef86a6295d353dc3bb6c80550665ba2c3bef3a9feab46074d12a9af8f"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0591df2e856ad583644b40a2b99fb522f93543c65e64b771241dda6d1cfdc96b"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f277801f55b2f3923ef2de51ab94689a0671a4524bf7b611de979f308a54cd6f"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:893fdfd4f66ebb67f33da89eb1bd1674b7b30442fdee84db87f6cb9074bf0ce9"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fe2651258c1f1afa9b66f44bf82f639d5f83034f9804877a1bbbae2120539ad1"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:ace21f7a78519d8e889b1240489cd021c5355c496cb151b479b741a4c27f0a25"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cb5acf24590bc5e57027283b015950d713f9e4d155fda5cfa71adef3b3a84502"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:67ea46fa8cc78174bad09d66b9a4b98d3068e85de677e3c71ed931a1de28171f"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:44e741d785de57d1a7bae03599c1cbc7335d0b060a35e60c44c382566e22782e"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-win32.whl", hash = "sha256:b1fe6001baa9fa36bcb565e24e88830718f6c90896b91ceffcb48881e3adddbc"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-win_amd64.whl", hash = "sha256:83b8cc6336709fa5db0579189bfd125df280a554af544b2dc1c7da9cdad7e44d"}, + {file = "rapidfuzz-3.14.1-cp313-cp313-win_arm64.whl", hash = "sha256:cf75769662eadf5f9bd24e865c19e5ca7718e879273dce4e7b3b5824c4da0eb4"}, + {file = "rapidfuzz-3.14.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:d937dbeda71c921ef6537c6d41a84f1b8112f107589c9977059de57a1d726dd6"}, + {file = "rapidfuzz-3.14.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:7a2d80cc1a4fcc7e259ed4f505e70b36433a63fa251f1bb69ff279fe376c5efd"}, + {file = "rapidfuzz-3.14.1-cp313-cp313t-win32.whl", hash = "sha256:40875e0c06f1a388f1cab3885744f847b557e0b1642dfc31ff02039f9f0823ef"}, + {file = "rapidfuzz-3.14.1-cp313-cp313t-win_amd64.whl", hash = "sha256:876dc0c15552f3d704d7fb8d61bdffc872ff63bedf683568d6faad32e51bbce8"}, + {file = "rapidfuzz-3.14.1-cp313-cp313t-win_arm64.whl", hash = "sha256:61458e83b0b3e2abc3391d0953c47d6325e506ba44d6a25c869c4401b3bc222c"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e84d9a844dc2e4d5c4cabd14c096374ead006583304333c14a6fbde51f612a44"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:40301b93b99350edcd02dbb22e37ca5f2a75d0db822e9b3c522da451a93d6f27"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fedd5097a44808dddf341466866e5c57a18a19a336565b4ff50aa8f09eb528f6"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e3e61c9e80d8c26709d8aa5c51fdd25139c81a4ab463895f8a567f8347b0548"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-manylinux_2_26_s390x.manylinux_2_28_s390x.whl", hash = "sha256:da011a373722fac6e64687297a1d17dc8461b82cb12c437845d5a5b161bc24b9"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5967d571243cfb9ad3710e6e628ab68c421a237b76e24a67ac22ee0ff12784d6"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:474f416cbb9099676de54aa41944c154ba8d25033ee460f87bb23e54af6d01c9"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ae2d57464b59297f727c4e201ea99ec7b13935f1f056c753e8103da3f2fc2404"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:57047493a1f62f11354c7143c380b02f1b355c52733e6b03adb1cb0fe8fb8816"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4acc20776f225ee37d69517a237c090b9fa7e0836a0b8bc58868e9168ba6ef6f"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:4373f914ff524ee0146919dea96a40a8200ab157e5a15e777a74a769f73d8a4a"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:37017b84953927807847016620d61251fe236bd4bcb25e27b6133d955bb9cafb"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-win32.whl", hash = "sha256:c8d1dd1146539e093b84d0805e8951475644af794ace81d957ca612e3eb31598"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-win_amd64.whl", hash = "sha256:f51c7571295ea97387bac4f048d73cecce51222be78ed808263b45c79c40a440"}, + {file = "rapidfuzz-3.14.1-cp314-cp314-win_arm64.whl", hash = "sha256:01eab10ec90912d7d28b3f08f6c91adbaf93458a53f849ff70776ecd70dd7a7a"}, + {file = "rapidfuzz-3.14.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:60879fcae2f7618403c4c746a9a3eec89327d73148fb6e89a933b78442ff0669"}, + {file = "rapidfuzz-3.14.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:f94d61e44db3fc95a74006a394257af90fa6e826c900a501d749979ff495d702"}, + {file = "rapidfuzz-3.14.1-cp314-cp314t-win32.whl", hash = "sha256:93b6294a3ffab32a9b5f9b5ca048fa0474998e7e8bb0f2d2b5e819c64cb71ec7"}, + {file = "rapidfuzz-3.14.1-cp314-cp314t-win_amd64.whl", hash = "sha256:6cb56b695421538fdbe2c0c85888b991d833b8637d2f2b41faa79cea7234c000"}, + {file = "rapidfuzz-3.14.1-cp314-cp314t-win_arm64.whl", hash = "sha256:7cd312c380d3ce9d35c3ec9726b75eee9da50e8a38e89e229a03db2262d3d96b"}, + {file = "rapidfuzz-3.14.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:673ce55a9be5b772dade911909e42382c0828b8a50ed7f9168763fa6b9f7054d"}, + {file = "rapidfuzz-3.14.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:45c62ada1980ebf4c64c4253993cc8daa018c63163f91db63bb3af69cb74c2e3"}, + {file = "rapidfuzz-3.14.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:4d51efb29c0df0d4f7f64f672a7624c2146527f0745e3572098d753676538800"}, + {file = "rapidfuzz-3.14.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4a21ccdf1bd7d57a1009030527ba8fae1c74bf832d0a08f6b67de8f5c506c96f"}, + {file = "rapidfuzz-3.14.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:589fb0af91d3aff318750539c832ea1100dbac2c842fde24e42261df443845f6"}, + {file = "rapidfuzz-3.14.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:a4f18092db4825f2517d135445015b40033ed809a41754918a03ef062abe88a0"}, + {file = "rapidfuzz-3.14.1.tar.gz", hash = "sha256:b02850e7f7152bd1edff27e9d584505b84968cacedee7a734ec4050c655a803c"}, +] + +[package.extras] +all = ["numpy"] + +[[package]] +name = "readme-renderer" +version = "44.0" +description = "readme_renderer is a library for rendering readme descriptions for Warehouse" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, + {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, +] + +[package.dependencies] +docutils = ">=0.21.2" +nh3 = ">=0.2.14" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + +[[package]] +name = "requests" +version = "2.32.5" +description = "Python HTTP for Humans." +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "requests-2.32.5-py3-none-any.whl", hash = "sha256:2462f94637a34fd532264295e186976db0f5d453d1cdd31473c85a6a161affb6"}, + {file = "requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf"}, +] + +[package.dependencies] +certifi = ">=2017.4.17" +charset_normalizer = ">=2,<4" +idna = ">=2.5,<4" +urllib3 = ">=1.21.1,<3" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)"] +use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] + +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main", "build"] +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + +[[package]] +name = "rfc3986" +version = "2.0.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = ">=3.7" +groups = ["main", "build"] +files = [ + {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, + {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, +] + +[package.extras] +idna2008 = ["idna"] + +[[package]] +name = "rich" +version = "14.1.0" +description = "Render rich text, tables, progress bars, syntax highlighting, markdown and more to the terminal" +optional = false +python-versions = ">=3.8.0" +groups = ["main", "bandit", "build"] +files = [ + {file = "rich-14.1.0-py3-none-any.whl", hash = "sha256:536f5f1785986d6dbdea3c75205c473f970777b4a0d6c6dd1b696aa05a3fa04f"}, + {file = "rich-14.1.0.tar.gz", hash = "sha256:e497a48b844b0320d45007cdebfeaeed8db2a4f4bcf49f15e455cfc4af11eaa8"}, +] + +[package.dependencies] +markdown-it-py = ">=2.2.0" +pygments = ">=2.13.0,<3.0.0" + +[package.extras] +jupyter = ["ipywidgets (>=7.5.1,<9)"] + +[[package]] +name = "ruff" +version = "0.13.0" +description = "An extremely fast Python linter and code formatter, written in Rust." +optional = false +python-versions = ">=3.7" +groups = ["main", "lint"] +files = [ + {file = "ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004"}, + {file = "ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9"}, + {file = "ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823"}, + {file = "ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768"}, + {file = "ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb"}, + {file = "ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e"}, + {file = "ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60"}, +] + +[[package]] +name = "secretstorage" +version = "3.4.0" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.10" +groups = ["main", "build"] +files = [ + {file = "secretstorage-3.4.0-py3-none-any.whl", hash = "sha256:0e3b6265c2c63509fb7415717607e4b2c9ab767b7f344a57473b779ca13bd02e"}, + {file = "secretstorage-3.4.0.tar.gz", hash = "sha256:c46e216d6815aff8a8a18706a2fbfd8d53fcbb0dce99301881687a1b0289ef7c"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and sys_platform == \"linux\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\""} + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + +[[package]] +name = "shellingham" +version = "1.5.4" +description = "Tool to Detect Surrounding Shell" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686"}, + {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, +] + +[[package]] +name = "sniffio" +version = "1.3.1" +description = "Sniff out which async library your code is running under" +optional = true +python-versions = ">=3.7" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2"}, + {file = "sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc"}, +] + +[[package]] +name = "stevedore" +version = "5.5.0" +description = "Manage dynamic plugins for Python applications" +optional = false +python-versions = ">=3.9" +groups = ["main", "bandit"] +files = [ + {file = "stevedore-5.5.0-py3-none-any.whl", hash = "sha256:18363d4d268181e8e8452e71a38cd77630f345b2ef6b4a8d5614dac5ee0d18cf"}, + {file = "stevedore-5.5.0.tar.gz", hash = "sha256:d31496a4f4df9825e1a1e4f1f74d19abb0154aff311c3b376fcc89dae8fccd73"}, +] + +[[package]] +name = "tomli" +version = "2.2.1" +description = "A lil' TOML parser" +optional = false +python-versions = ">=3.8" +groups = ["main", "bandit", "test", "type"] +files = [ + {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"}, +] +markers = {main = "python_full_version <= \"3.11.0a6\"", bandit = "python_version == \"3.10\"", test = "python_full_version <= \"3.11.0a6\"", type = "python_version == \"3.10\""} + +[[package]] +name = "tomlkit" +version = "0.13.3" +description = "Style preserving TOML library" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, + {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, +] + +[[package]] +name = "tox" +version = "4.30.2" +description = "tox is a generic virtualenv management and test command line tool" +optional = false +python-versions = ">=3.9" +groups = ["main", "test"] +files = [ + {file = "tox-4.30.2-py3-none-any.whl", hash = "sha256:efd261a42e8c82a59f9026320a80a067f27f44cad2e72a6712010c311d31176b"}, + {file = "tox-4.30.2.tar.gz", hash = "sha256:772925ad6c57fe35c7ed5ac3e958ac5ced21dff597e76fc40c1f5bf3cd1b6a2e"}, +] + +[package.dependencies] +cachetools = ">=6.1" +chardet = ">=5.2" +colorama = ">=0.4.6" +filelock = ">=3.18" +packaging = ">=25" +platformdirs = ">=4.3.8" +pluggy = ">=1.6" +pyproject-api = ">=1.9.1" +tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} +typing-extensions = {version = ">=4.14.1", markers = "python_version < \"3.11\""} +virtualenv = ">=20.31.2" + +[[package]] +name = "trove-classifiers" +version = "2025.9.11.17" +description = "Canonical source for classifiers on PyPI (pypi.org)." +optional = true +python-versions = "*" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "trove_classifiers-2025.9.11.17-py3-none-any.whl", hash = "sha256:5d392f2d244deb1866556457d6f3516792124a23d1c3a463a2e8668a5d1c15dd"}, + {file = "trove_classifiers-2025.9.11.17.tar.gz", hash = "sha256:931ca9841a5e9c9408bc2ae67b50d28acf85bef56219b56860876dd1f2d024dd"}, +] + +[[package]] +name = "twine" +version = "6.2.0" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "twine-6.2.0-py3-none-any.whl", hash = "sha256:418ebf08ccda9a8caaebe414433b0ba5e25eb5e4a927667122fbe8f829f985d8"}, + {file = "twine-6.2.0.tar.gz", hash = "sha256:e5ed0d2fd70c9959770dce51c8f39c8945c574e18173a7b81802dab51b4b75cf"}, +] + +[package.dependencies] +id = "*" +keyring = {version = ">=21.2.0", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} +packaging = ">=24.0" +readme-renderer = ">=35.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +rich = ">=12.0.0" +urllib3 = ">=1.26.0" + +[package.extras] +keyring = ["keyring (>=21.2.0)"] + +[[package]] +name = "typing-extensions" +version = "4.15.0" +description = "Backported and Experimental Type Hints for Python 3.9+" +optional = false +python-versions = ">=3.9" +groups = ["main", "build", "test", "type"] +files = [ + {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, + {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, +] +markers = {build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and python_version == \"3.10\"", test = "python_version == \"3.10\""} + +[[package]] +name = "typing-inspection" +version = "0.4.1" +description = "Runtime typing introspection tools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51"}, + {file = "typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28"}, +] + +[package.dependencies] +typing-extensions = ">=4.12.0" + +[[package]] +name = "urllib3" +version = "2.5.0" +description = "HTTP library with thread-safe connection pooling, file post, and more." +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc"}, + {file = "urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760"}, +] + +[package.extras] +brotli = ["brotli (>=1.0.9) ; platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; platform_python_implementation != \"CPython\""] +h2 = ["h2 (>=4,<5)"] +socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] +zstd = ["zstandard (>=0.18.0)"] + +[[package]] +name = "virtualenv" +version = "20.34.0" +description = "Virtual Python Environment builder" +optional = false +python-versions = ">=3.8" +groups = ["main", "test"] +files = [ + {file = "virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026"}, + {file = "virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a"}, +] + +[package.dependencies] +distlib = ">=0.3.7,<1" +filelock = ">=3.12.2,<4" +platformdirs = ">=3.9.1,<5" +typing-extensions = {version = ">=4.13.2", markers = "python_version < \"3.11\""} + +[package.extras] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8) ; platform_python_implementation == \"PyPy\" or platform_python_implementation == \"GraalVM\" or platform_python_implementation == \"CPython\" and sys_platform == \"win32\" and python_version >= \"3.13\"", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10) ; platform_python_implementation == \"CPython\""] + +[[package]] +name = "xattr" +version = "1.2.0" +description = "Python wrapper for extended filesystem attributes" +optional = true +python-versions = ">=3.8" +groups = ["main"] +markers = "extra == \"build\" and sys_platform == \"darwin\"" +files = [ + {file = "xattr-1.2.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3df4d8d91e2996c3c72a390ec82e8544acdcb6c7df67b954f1736ff37ea4293e"}, + {file = "xattr-1.2.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f5eec248976bbfa6c23df25d4995413df57dccf4161f6cbae36f643e99dbc397"}, + {file = "xattr-1.2.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fafecfdedf7e8d455443bec2c3edab8a93d64672619cd1a4ee043a806152e19c"}, + {file = "xattr-1.2.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c229e245c6c9a85d2fd7d07531498f837dd34670e556b552f73350f11edf000c"}, + {file = "xattr-1.2.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:376631e2383918fbc3dc9bcaeb9a533e319322d2cff1c119635849edf74e1126"}, + {file = "xattr-1.2.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2fbae24ab22afe078d549645501ecacaa17229e0b7769c8418fad69b51ad37c9"}, + {file = "xattr-1.2.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a161160211081d765ac41fa056f4f9b1051f027f08188730fbc9782d0dce623e"}, + {file = "xattr-1.2.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:a542acf6c4e8221664b51b35e0160c44bd0ed1f2fd80019476f7698f4911e560"}, + {file = "xattr-1.2.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:034f075fc5a9391a1597a6c9a21cb57b688680f0f18ecf73b2efc22b8d330cff"}, + {file = "xattr-1.2.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:00c26c14c90058338993bb2d3e1cebf562e94ec516cafba64a8f34f74b9d18b4"}, + {file = "xattr-1.2.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b4f43dc644db87d5eb9484a9518c34a864cb2e588db34cffc42139bf55302a1c"}, + {file = "xattr-1.2.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c7602583fc643ca76576498e2319c7cef0b72aef1936701678589da6371b731b"}, + {file = "xattr-1.2.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90c3ad4a9205cceb64ec54616aa90aa42d140c8ae3b9710a0aaa2843a6f1aca7"}, + {file = "xattr-1.2.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83d87cfe19cd606fc0709d45a4d6efc276900797deced99e239566926a5afedf"}, + {file = "xattr-1.2.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c67dabd9ddc04ead63fbc85aed459c9afcc24abfc5bb3217fff7ec9a466faacb"}, + {file = "xattr-1.2.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9a18ee82d8ba2c17f1e8414bfeb421fa763e0fb4acbc1e124988ca1584ad32d5"}, + {file = "xattr-1.2.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:38de598c47b85185e745986a061094d2e706e9c2d9022210d2c738066990fe91"}, + {file = "xattr-1.2.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:15e754e854bdaac366ad3f1c8fbf77f6668e8858266b4246e8c5f487eeaf1179"}, + {file = "xattr-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:daff0c1f5c5e4eaf758c56259c4f72631fa9619875e7a25554b6077dc73da964"}, + {file = "xattr-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:109b11fb3f73a0d4e199962f11230ab5f462e85a8021874f96c1732aa61148d5"}, + {file = "xattr-1.2.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:7c7c12968ce0bf798d8ba90194cef65de768bee9f51a684e022c74cab4218305"}, + {file = "xattr-1.2.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d37989dabf25ff18773e4aaeebcb65604b9528f8645f43e02bebaa363e3ae958"}, + {file = "xattr-1.2.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:165de92b0f2adafb336f936931d044619b9840e35ba01079f4dd288747b73714"}, + {file = "xattr-1.2.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82191c006ae4c609b22b9aea5f38f68fff022dc6884c4c0e1dba329effd4b288"}, + {file = "xattr-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2b2e9c87dc643b09d86befad218e921f6e65b59a4668d6262b85308de5dbd1dd"}, + {file = "xattr-1.2.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:14edd5d47d0bb92b23222c0bb6379abbddab01fb776b2170758e666035ecf3aa"}, + {file = "xattr-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:12183d5eb104d4da787638c7dadf63b718472d92fec6dbe12994ea5d094d7863"}, + {file = "xattr-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:c385ea93a18aeb6443a719eb6a6b1d7f7b143a4d1f2b08bc4fadfc429209e629"}, + {file = "xattr-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2d39d7b36842c67ab3040bead7eb6d601e35fa0d6214ed20a43df4ec30b6f9f9"}, + {file = "xattr-1.2.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:320ef856bb817f4c40213b6de956dc440d0f23cdc62da3ea02239eb5147093f8"}, + {file = "xattr-1.2.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:26d306bfb3b5641726f2ee0da6f63a2656aa7fdcfd15de61c476e3ca6bc3277e"}, + {file = "xattr-1.2.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c67e70d5d8136d328ad13f85b887ffa97690422f1a11fb29ab2f702cf66e825a"}, + {file = "xattr-1.2.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8904d3539afe1a84fc0b7f02fa91da60d2505adf2d5951dc855bf9e75fe322b2"}, + {file = "xattr-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:2520516c1d058895eae00b2b2f10833514caea6dc6802eef1e431c474b5317ad"}, + {file = "xattr-1.2.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:29d06abbef4024b7469fcd0d4ade6d2290582350a4df95fcc48fa48b2e83246b"}, + {file = "xattr-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:093c75f7d9190be355b8e86da3f460b9bfe3d6a176f92852d44dcc3289aa10dc"}, + {file = "xattr-1.2.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:2ee3901db48de913dcef004c5d7b477a1f4aadff997445ef62907b10fdad57de"}, + {file = "xattr-1.2.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b837898a5225c7f7df731783cd78bae2ed81b84bacf020821f1cd2ab2d74de58"}, + {file = "xattr-1.2.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:cedc281811e424ecf6a14208532f7ac646866f91f88e8eadd00d8fe535e505fd"}, + {file = "xattr-1.2.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cf60577caa248f539e4e646090b10d6ad1f54189de9a7f1854c23fdef28f574e"}, + {file = "xattr-1.2.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:363724f33510d2e7c7e080b389271a1241cb4929a1d9294f89721152b4410972"}, + {file = "xattr-1.2.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:97db00596865845efb72f3d565a1f82b01006c5bf5a87d8854a6afac43502593"}, + {file = "xattr-1.2.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:0b199ba31078f3e4181578595cd60400ee055b4399672169ceee846d33ff26de"}, + {file = "xattr-1.2.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:b19472dc38150ac09a478c71092738d86882bc9ff687a4a8f7d1a25abce20b5e"}, + {file = "xattr-1.2.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:79f7823b30ed557e0e7ffd9a6b1a821a22f485f5347e54b8d24c4a34b7545ba4"}, + {file = "xattr-1.2.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:8eee258f5774933cb972cff5c3388166374e678980d2a1f417d7d6f61d9ae172"}, + {file = "xattr-1.2.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2a9de621eadf0466c391363bd6ed903b1a1bcd272422b5183fd06ef79d05347b"}, + {file = "xattr-1.2.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:bc714f236f17c57c510ae9ada9962d8e4efc9f9ea91504e2c6a09008f3918ddf"}, + {file = "xattr-1.2.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:545e0ad3f706724029efd23dec58fb358422ae68ab4b560b712aedeaf40446a0"}, + {file = "xattr-1.2.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:200bb3cdba057cb721b727607bc340a74c28274f4a628a26011f574860f5846b"}, + {file = "xattr-1.2.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9b0b27c889cc9ff0dba62ac8a2eef98f4911c1621e4e8c409d5beb224c4c227c"}, + {file = "xattr-1.2.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ea7cf8afd717853ad78eba8ca83ff66a53484ba2bb2a4283462bc5c767518174"}, + {file = "xattr-1.2.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:02fa813db054bbb7a61c570ae025bd01c36fc20727b40f49031feb930234bc72"}, + {file = "xattr-1.2.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:2827e23d7a1a20f31162c47ab4bd341a31e83421121978c4ab2aad5cd79ea82b"}, + {file = "xattr-1.2.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:29ae44247d46e63671311bf7e700826a97921278e2c0c04c2d11741888db41b8"}, + {file = "xattr-1.2.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:629c42c1dd813442d90f281f69b88ef0c9625f604989bef8411428671f70f43e"}, + {file = "xattr-1.2.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:549f8fbda5da48cafc81ba6ab7bb8e8e14c4b0748c37963dc504bcae505474b7"}, + {file = "xattr-1.2.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa83e677b5f92a3c5c86eaf875e9d3abbc43887ff1767178def865fa9f12a3a0"}, + {file = "xattr-1.2.0-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb669f01627962ce2bc556f19d421162247bc2cad0d4625d6ea5eb32af4cf29b"}, + {file = "xattr-1.2.0-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:212156aa5fb987a53211606bc09e6fea3eda3855af9f2940e40df5a2a592425a"}, + {file = "xattr-1.2.0-pp38-pypy38_pp73-macosx_11_0_arm64.whl", hash = "sha256:7dc4fa9448a513077c5ccd1ce428ff0682cdddfc71301dbbe4ee385c74517f73"}, + {file = "xattr-1.2.0-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e4b93f2e74793b61c0a7b7bdef4a3813930df9c01eda72fad706b8db7658bc2"}, + {file = "xattr-1.2.0-pp38-pypy38_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dddd5f6d0bb95b099d6a3888c248bf246525647ccb8cf9e8f0fc3952e012d6fb"}, + {file = "xattr-1.2.0-pp38-pypy38_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:68fbdffebe8c398a82c84ecf5e6f6a3adde9364f891cba066e58352af404a45c"}, + {file = "xattr-1.2.0-pp39-pypy39_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c9ee84de7cd4a6d61b0b79e2f58a6bdb13b03dbad948489ebb0b73a95caee7ae"}, + {file = "xattr-1.2.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:5594fcbc38fdbb3af16a8ad18c37c81c8814955f0d636be857a67850cd556490"}, + {file = "xattr-1.2.0-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:017aac8005e1e84d5efa4b86c0896c6eb96f2331732d388600a5b999166fec1c"}, + {file = "xattr-1.2.0-pp39-pypy39_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d27a64f695440450c119ae4bc8f54b0b726a812ebea1666fff3873236936f36"}, + {file = "xattr-1.2.0-pp39-pypy39_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f7e7067e1a400ad4485536a9e84c3330373086b2324fafa26d07527eeb4b175"}, + {file = "xattr-1.2.0.tar.gz", hash = "sha256:a64c8e21eff1be143accf80fd3b8fde3e28a478c37da298742af647ac3e5e0a7"}, +] + +[package.dependencies] +cffi = ">=1.16.0" + +[package.extras] +test = ["pytest"] + +[[package]] +name = "zipp" +version = "3.23.0" +description = "Backport of pathlib-compatible object wrapper for zip files" +optional = false +python-versions = ">=3.9" +groups = ["main", "build"] +files = [ + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, +] +markers = {main = "(extra == \"build\" or platform_machine != \"ppc64le\" and platform_machine != \"s390x\") and python_version < \"3.12\"", build = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version < \"3.12\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +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)"] +test = ["big-O", "jaraco.functools", "jaraco.itertools", "jaraco.test", "more_itertools", "pytest (>=6,!=8.1.*)", "pytest-ignore-flaky"] +type = ["pytest-mypy"] + +[[package]] +name = "zstandard" +version = "0.25.0" +description = "Zstandard bindings for Python" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"build\"" +files = [ + {file = "zstandard-0.25.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:e59fdc271772f6686e01e1b3b74537259800f57e24280be3f29c8a0deb1904dd"}, + {file = "zstandard-0.25.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4d441506e9b372386a5271c64125f72d5df6d2a8e8a2a45a0ae09b03cb781ef7"}, + {file = "zstandard-0.25.0-cp310-cp310-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:ab85470ab54c2cb96e176f40342d9ed41e58ca5733be6a893b730e7af9c40550"}, + {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e05ab82ea7753354bb054b92e2f288afb750e6b439ff6ca78af52939ebbc476d"}, + {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:78228d8a6a1c177a96b94f7e2e8d012c55f9c760761980da16ae7546a15a8e9b"}, + {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:2b6bd67528ee8b5c5f10255735abc21aa106931f0dbaf297c7be0c886353c3d0"}, + {file = "zstandard-0.25.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4b6d83057e713ff235a12e73916b6d356e3084fd3d14ced499d84240f3eecee0"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:9174f4ed06f790a6869b41cba05b43eeb9a35f8993c4422ab853b705e8112bbd"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:25f8f3cd45087d089aef5ba3848cd9efe3ad41163d3400862fb42f81a3a46701"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3756b3e9da9b83da1796f8809dd57cb024f838b9eeafde28f3cb472012797ac1"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:81dad8d145d8fd981b2962b686b2241d3a1ea07733e76a2f15435dfb7fb60150"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:a5a419712cf88862a45a23def0ae063686db3d324cec7edbe40509d1a79a0aab"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:e7360eae90809efd19b886e59a09dad07da4ca9ba096752e61a2e03c8aca188e"}, + {file = "zstandard-0.25.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:75ffc32a569fb049499e63ce68c743155477610532da1eb38e7f24bf7cd29e74"}, + {file = "zstandard-0.25.0-cp310-cp310-win32.whl", hash = "sha256:106281ae350e494f4ac8a80470e66d1fe27e497052c8d9c3b95dc4cf1ade81aa"}, + {file = "zstandard-0.25.0-cp310-cp310-win_amd64.whl", hash = "sha256:ea9d54cc3d8064260114a0bbf3479fc4a98b21dffc89b3459edd506b69262f6e"}, + {file = "zstandard-0.25.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:933b65d7680ea337180733cf9e87293cc5500cc0eb3fc8769f4d3c88d724ec5c"}, + {file = "zstandard-0.25.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a3f79487c687b1fc69f19e487cd949bf3aae653d181dfb5fde3bf6d18894706f"}, + {file = "zstandard-0.25.0-cp311-cp311-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:0bbc9a0c65ce0eea3c34a691e3c4b6889f5f3909ba4822ab385fab9057099431"}, + {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:01582723b3ccd6939ab7b3a78622c573799d5d8737b534b86d0e06ac18dbde4a"}, + {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5f1ad7bf88535edcf30038f6919abe087f606f62c00a87d7e33e7fc57cb69fcc"}, + {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:06acb75eebeedb77b69048031282737717a63e71e4ae3f77cc0c3b9508320df6"}, + {file = "zstandard-0.25.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9300d02ea7c6506f00e627e287e0492a5eb0371ec1670ae852fefffa6164b072"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:bfd06b1c5584b657a2892a6014c2f4c20e0db0208c159148fa78c65f7e0b0277"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:f373da2c1757bb7f1acaf09369cdc1d51d84131e50d5fa9863982fd626466313"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:6c0e5a65158a7946e7a7affa6418878ef97ab66636f13353b8502d7ea03c8097"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:c8e167d5adf59476fa3e37bee730890e389410c354771a62e3c076c86f9f7778"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:98750a309eb2f020da61e727de7d7ba3c57c97cf6213f6f6277bb7fb42a8e065"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:22a086cff1b6ceca18a8dd6096ec631e430e93a8e70a9ca5efa7561a00f826fa"}, + {file = "zstandard-0.25.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:72d35d7aa0bba323965da807a462b0966c91608ef3a48ba761678cb20ce5d8b7"}, + {file = "zstandard-0.25.0-cp311-cp311-win32.whl", hash = "sha256:f5aeea11ded7320a84dcdd62a3d95b5186834224a9e55b92ccae35d21a8b63d4"}, + {file = "zstandard-0.25.0-cp311-cp311-win_amd64.whl", hash = "sha256:daab68faadb847063d0c56f361a289c4f268706b598afbf9ad113cbe5c38b6b2"}, + {file = "zstandard-0.25.0-cp311-cp311-win_arm64.whl", hash = "sha256:22a06c5df3751bb7dc67406f5374734ccee8ed37fc5981bf1ad7041831fa1137"}, + {file = "zstandard-0.25.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7b3c3a3ab9daa3eed242d6ecceead93aebbb8f5f84318d82cee643e019c4b73b"}, + {file = "zstandard-0.25.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:913cbd31a400febff93b564a23e17c3ed2d56c064006f54efec210d586171c00"}, + {file = "zstandard-0.25.0-cp312-cp312-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:011d388c76b11a0c165374ce660ce2c8efa8e5d87f34996aa80f9c0816698b64"}, + {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6dffecc361d079bb48d7caef5d673c88c8988d3d33fb74ab95b7ee6da42652ea"}, + {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:7149623bba7fdf7e7f24312953bcf73cae103db8cae49f8154dd1eadc8a29ecb"}, + {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:6a573a35693e03cf1d67799fd01b50ff578515a8aeadd4595d2a7fa9f3ec002a"}, + {file = "zstandard-0.25.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:5a56ba0db2d244117ed744dfa8f6f5b366e14148e00de44723413b2f3938a902"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:10ef2a79ab8e2974e2075fb984e5b9806c64134810fac21576f0668e7ea19f8f"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:aaf21ba8fb76d102b696781bddaa0954b782536446083ae3fdaa6f16b25a1c4b"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:1869da9571d5e94a85a5e8d57e4e8807b175c9e4a6294e3b66fa4efb074d90f6"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:809c5bcb2c67cd0ed81e9229d227d4ca28f82d0f778fc5fea624a9def3963f91"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f27662e4f7dbf9f9c12391cb37b4c4c3cb90ffbd3b1fb9284dadbbb8935fa708"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99c0c846e6e61718715a3c9437ccc625de26593fea60189567f0118dc9db7512"}, + {file = "zstandard-0.25.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:474d2596a2dbc241a556e965fb76002c1ce655445e4e3bf38e5477d413165ffa"}, + {file = "zstandard-0.25.0-cp312-cp312-win32.whl", hash = "sha256:23ebc8f17a03133b4426bcc04aabd68f8236eb78c3760f12783385171b0fd8bd"}, + {file = "zstandard-0.25.0-cp312-cp312-win_amd64.whl", hash = "sha256:ffef5a74088f1e09947aecf91011136665152e0b4b359c42be3373897fb39b01"}, + {file = "zstandard-0.25.0-cp312-cp312-win_arm64.whl", hash = "sha256:181eb40e0b6a29b3cd2849f825e0fa34397f649170673d385f3598ae17cca2e9"}, + {file = "zstandard-0.25.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ec996f12524f88e151c339688c3897194821d7f03081ab35d31d1e12ec975e94"}, + {file = "zstandard-0.25.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a1a4ae2dec3993a32247995bdfe367fc3266da832d82f8438c8570f989753de1"}, + {file = "zstandard-0.25.0-cp313-cp313-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:e96594a5537722fdfb79951672a2a63aec5ebfb823e7560586f7484819f2a08f"}, + {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:bfc4e20784722098822e3eee42b8e576b379ed72cca4a7cb856ae733e62192ea"}, + {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:457ed498fc58cdc12fc48f7950e02740d4f7ae9493dd4ab2168a47c93c31298e"}, + {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:fd7a5004eb1980d3cefe26b2685bcb0b17989901a70a1040d1ac86f1d898c551"}, + {file = "zstandard-0.25.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8e735494da3db08694d26480f1493ad2cf86e99bdd53e8e9771b2752a5c0246a"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3a39c94ad7866160a4a46d772e43311a743c316942037671beb264e395bdd611"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:172de1f06947577d3a3005416977cce6168f2261284c02080e7ad0185faeced3"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3c83b0188c852a47cd13ef3bf9209fb0a77fa5374958b8c53aaa699398c6bd7b"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1673b7199bbe763365b81a4f3252b8e80f44c9e323fc42940dc8843bfeaf9851"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:0be7622c37c183406f3dbf0cba104118eb16a4ea7359eeb5752f0794882fc250"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:5f5e4c2a23ca271c218ac025bd7d635597048b366d6f31f420aaeb715239fc98"}, + {file = "zstandard-0.25.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f187a0bb61b35119d1926aee039524d1f93aaf38a9916b8c4b78ac8514a0aaf"}, + {file = "zstandard-0.25.0-cp313-cp313-win32.whl", hash = "sha256:7030defa83eef3e51ff26f0b7bfb229f0204b66fe18e04359ce3474ac33cbc09"}, + {file = "zstandard-0.25.0-cp313-cp313-win_amd64.whl", hash = "sha256:1f830a0dac88719af0ae43b8b2d6aef487d437036468ef3c2ea59c51f9d55fd5"}, + {file = "zstandard-0.25.0-cp313-cp313-win_arm64.whl", hash = "sha256:85304a43f4d513f5464ceb938aa02c1e78c2943b29f44a750b48b25ac999a049"}, + {file = "zstandard-0.25.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:e29f0cf06974c899b2c188ef7f783607dbef36da4c242eb6c82dcd8b512855e3"}, + {file = "zstandard-0.25.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:05df5136bc5a011f33cd25bc9f506e7426c0c9b3f9954f056831ce68f3b6689f"}, + {file = "zstandard-0.25.0-cp314-cp314-manylinux2010_i686.manylinux_2_12_i686.manylinux_2_28_i686.whl", hash = "sha256:f604efd28f239cc21b3adb53eb061e2a205dc164be408e553b41ba2ffe0ca15c"}, + {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:223415140608d0f0da010499eaa8ccdb9af210a543fac54bce15babbcfc78439"}, + {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:2e54296a283f3ab5a26fc9b8b5d4978ea0532f37b231644f367aa588930aa043"}, + {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ca54090275939dc8ec5dea2d2afb400e0f83444b2fc24e07df7fdef677110859"}, + {file = "zstandard-0.25.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e09bb6252b6476d8d56100e8147b803befa9a12cea144bbe629dd508800d1ad0"}, + {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:a9ec8c642d1ec73287ae3e726792dd86c96f5681eb8df274a757bf62b750eae7"}, + {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4089a10e598eae6393756b036e0f419e8c1d60f44a831520f9af41c14216cf2"}, + {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:f67e8f1a324a900e75b5e28ffb152bcac9fbed1cc7b43f99cd90f395c4375344"}, + {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:9654dbc012d8b06fc3d19cc825af3f7bf8ae242226df5f83936cb39f5fdc846c"}, + {file = "zstandard-0.25.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4203ce3b31aec23012d3a4cf4a2ed64d12fea5269c49aed5e4c3611b938e4088"}, + {file = "zstandard-0.25.0-cp314-cp314-win32.whl", hash = "sha256:da469dc041701583e34de852d8634703550348d5822e66a0c827d39b05365b12"}, + {file = "zstandard-0.25.0-cp314-cp314-win_amd64.whl", hash = "sha256:c19bcdd826e95671065f8692b5a4aa95c52dc7a02a4c5a0cac46deb879a017a2"}, + {file = "zstandard-0.25.0-cp314-cp314-win_arm64.whl", hash = "sha256:d7541afd73985c630bafcd6338d2518ae96060075f9463d7dc14cfb33514383d"}, + {file = "zstandard-0.25.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b9af1fe743828123e12b41dd8091eca1074d0c1569cc42e6e1eee98027f2bbd0"}, + {file = "zstandard-0.25.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:4b14abacf83dfb5c25eb4e4a79520de9e7e205f72c9ee7702f91233ae57d33a2"}, + {file = "zstandard-0.25.0-cp39-cp39-manylinux2010_i686.manylinux2014_i686.manylinux_2_12_i686.manylinux_2_17_i686.whl", hash = "sha256:a51ff14f8017338e2f2e5dab738ce1ec3b5a851f23b18c1ae1359b1eecbee6df"}, + {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3b870ce5a02d4b22286cf4944c628e0f0881b11b3f14667c1d62185a99e04f53"}, + {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:05353cef599a7b0b98baca9b068dd36810c3ef0f42bf282583f438caf6ddcee3"}, + {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:19796b39075201d51d5f5f790bf849221e58b48a39a5fc74837675d8bafc7362"}, + {file = "zstandard-0.25.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:53e08b2445a6bc241261fea89d065536f00a581f02535f8122eba42db9375530"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:1f3689581a72eaba9131b1d9bdbfe520ccd169999219b41000ede2fca5c1bfdb"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d8c56bb4e6c795fc77d74d8e8b80846e1fb8292fc0b5060cd8131d522974b751"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:53f94448fe5b10ee75d246497168e5825135d54325458c4bfffbaafabcc0a577"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:c2ba942c94e0691467ab901fc51b6f2085ff48f2eea77b1a48240f011e8247c7"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:07b527a69c1e1c8b5ab1ab14e2afe0675614a09182213f21a0717b62027b5936"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:51526324f1b23229001eb3735bc8c94f9c578b1bd9e867a0a646a3b17109f388"}, + {file = "zstandard-0.25.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89c4b48479a43f820b749df49cd7ba2dbc2b1b78560ecb5ab52985574fd40b27"}, + {file = "zstandard-0.25.0-cp39-cp39-win32.whl", hash = "sha256:1cd5da4d8e8ee0e88be976c294db744773459d51bb32f707a0f166e5ad5c8649"}, + {file = "zstandard-0.25.0-cp39-cp39-win_amd64.whl", hash = "sha256:37daddd452c0ffb65da00620afb8e17abd4adaae6ce6310702841760c2c26860"}, + {file = "zstandard-0.25.0.tar.gz", hash = "sha256:7713e1179d162cf5c7906da876ec2ccb9c3a9dcbdffef0cc7f70c3667a205f0b"}, +] + +[package.extras] +cffi = ["cffi (>=1.17,<2.0) ; platform_python_implementation != \"PyPy\" and python_version < \"3.14\"", "cffi (>=2.0.0b) ; platform_python_implementation != \"PyPy\" and python_version >= \"3.14\""] + +[extras] +bandit = ["bandit"] +build = ["poetry", "twine"] +lint = ["ruff"] +test = ["coverage", "pytest", "pytest-cov", "pytest-env", "pytest-mock", "tox"] +type = ["mypy"] + +[metadata] +lock-version = "2.1" +python-versions = ">=3.10,<4.0" +content-hash = "104514a4a31881642b004e6fef032ad7a79f3b6da539d42db88484f6ba6d14b2" diff --git a/file_checker_python/file_checker_python_wrapper/pyproject.toml b/file_checker_python/file_checker_python_wrapper/pyproject.toml new file mode 100644 index 0000000..82413cd --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/pyproject.toml @@ -0,0 +1,189 @@ +[build-system] +requires = ["poetry-core>=2.0.0,<3.0.0", "poetry-dynamic-versioning>=1.0.0,<2.0.0"] +build-backend = "poetry_dynamic_versioning.backend" + +[project] +name = "argofilechecker-python-wrapper" +version = "0.0.0" +description = "Python wrapper for Argo file checker" +authors = [ + {name = "Yvan Lubac",email = "yvan.lubac@euro-argo.eu"} +] +readme = "README.md" + +[tool.poetry] +packages = [{include = "argofilechecker_python_wrapper", from = "src"}] + +[tool.poetry-dynamic-versioning] +enable = true +vcs = "git" +style = "semver" + +[tool.poetry.dependencies] +python = ">=3.10,<4.0" +pydantic = "^2.11.9" +defusedxml = "^0.7.1" +# Specify the optional dependencies that will be used below as "extras" +pytest = { version = ">=8.4.2,<9.0.0", optional = true } +pytest-cov = { version = ">=7.0.0,<8.0.0", optional = true } +pytest-mock = { version = ">=3.15.1,<4.0.0", optional = true } +coverage = { version = ">=7.10.6,<8.0.0", extras = ["xml"], optional = true } +tox = { version = ">=4.30.2,<5.0.0", optional = true } +ruff = { version = ">=0.13.0,<0.14.0", optional = true } +mypy = { version = ">=1.18.1,<2.0.0", optional = true } +bandit = { version = ">=1.8.6,<2.0.0", extras = ["toml"], optional = true } +poetry = { version = ">=2.0.0", optional = true } +twine = { version = ">=6.2.0,<7.0.0", optional = true } +pytest-env = "^1.1.5" + + +[tool.poetry.extras] +test = ["pytest", "pytest-cov", "pytest-mock", "pytest-env", "coverage", "tox"] +lint = ["ruff"] +type = ["mypy"] +bandit = ["bandit"] +build = ["poetry", "twine"] + + +[dependency-groups] +lint = [ + "ruff (>=0.13.0,<0.14.0)" +] +build = [ + "twine (>=6.2.0,<7.0.0)" +] +type = [ + "mypy (>=1.18.1,<2.0.0)" +] +test = [ + "pytest (>=8.4.2,<9.0.0)", + "pytest-cov (>=7.0.0,<8.0.0)", + "pytest-mock (>=3.15.1,<4.0.0)", + "tox (>=4.30.2,<5.0.0)", + "coverage[xml] (>=7.10.6,<8.0.0)" +] +bandit = [ + "bandit[toml] (>=1.8.6,<2.0.0)" +] + +[tool.coverage.paths] +source = [ + "src/argofilechecker_python_wrapper", + "**/argofilechecker_python_wrapper" +] + +[tool.setuptools.packages.find] +namespaces = false + +[tool.bandit] +exclude_dirs = ["tests"] + +[tool.ruff] +target-version = "py312" +line-length = 120 +indent-width = 4 +exclude = [ + ".bzr", + ".direnv", + ".eggs", + ".git", + ".git-rewrite", + ".hg", + ".ipynb_checkpoints", + ".mypy_cache", + ".nox", + ".pants.d", + ".pyenv", + ".pytest_cache", + ".pytype", + ".ruff_cache", + ".svn", + ".tox", + ".venv", + ".vscode", + "__pypackages__", + "_build", + "buck-out", + "build", + "dist", + "node_modules", + "site-packages", + "venv", +] + +[tool.ruff.lint] +select = [ + "F", + "E", + "C90", + "I", + "N", + "D", + "ERA", + "PD", + "PGH", + "PL", + "TRY", + "FLY", + "NPY", + "PERF", + "FURB", + "RUF" +] +ignore = [ + "D203", # Conflict with D211 - prefer no-blank-line-before-class. + "D213", # Conflict with D213 - prefer multi-line-summary-first-line. +] +fixable = ["ALL"] +unfixable = [] +# Allow unused variables when underscore-prefixed. +dummy-variable-rgx = "^(_+|(_+[a-zA-Z0-9_]*[a-zA-Z0-9]+?))$" +isort.split-on-trailing-comma = false + +[tool.ruff.format] +quote-style = "double" +indent-style = "space" +skip-magic-trailing-comma = true +line-ending = "auto" +docstring-code-format = true +docstring-code-line-length = "dynamic" + +[tool.mypy] +python_version = "3.12" +plugins = ["pydantic.mypy"] +disallow_any_unimported = true +disallow_any_expr = true +disallow_any_decorated = true +disallow_any_generics = true +disallow_any_explicit = true +disallow_subclassing_any = true +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +no_implicit_optional = true +warn_unused_ignores = true +warn_no_return = true +warn_return_any = true +warn_redundant_casts = true +strict_equality = true +warn_unused_configs = true +ignore_missing_imports = true + +[tool.pydantic-mypy] +init_forbid_extra = true +init_typed = true +warn_required_dynamic_aliases = true + +[tool.pytest.ini_options] +testpaths = ["tests"] +markers = [ + "e2e: end-to-end tests which have to download data from GDAC."] + +[tool.pytest_env] +GDAC_FTP_HOST="ftp://ftp.ifremer.fr/ifremer/argo/dac" +SPECS_REPO_URL="https://github.com/OneArgo/ArgoFormatChecker.git" +SPECS_REPO_REF="main" +TEST_REPO_SUBDIR="file_checker_spec/" +JAR_URL="https://github.com/OneArgo/ArgoFormatChecker/releases/download/v2.9.3/file_checker_exec-2.9.3.jar" diff --git a/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/__init__.py b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/__init__.py new file mode 100644 index 0000000..bf75c97 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/__init__.py @@ -0,0 +1,9 @@ +"""File Checker Python wrapper package.""" + +__version__ = "0.0.0" # version will be updated automatically by poetry_dynamic_versioning + + +from .file_checker import FileChecker +from .models import PhaseType, ResultType, ValidationResult + +__all__ = ["FileChecker", "PhaseType", "ResultType", "ValidationResult", "__version__"] diff --git a/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/file_checker.py b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/file_checker.py new file mode 100644 index 0000000..7b42649 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/file_checker.py @@ -0,0 +1,311 @@ +"""FileChecker python wrapper module.""" + +import logging +import os +import subprocess # nosec B404 +import tempfile +from pathlib import Path +from typing import Dict, List, Optional +from xml.etree.ElementTree import Element, ElementTree, ParseError # nosec B405: this import is just for type. + +import defusedxml.ElementTree as DefusedET + +from .models import PhaseType, ResultType, ValidationResult + +logger = logging.getLogger(__name__) + + +class FileChecker: + """Python Wrapper for Argo Netcdf File Checker. + + File Checker will is run as subprocess so the location of the JAR file and specs must be provided as ENV variables + or explicitly in init. + The env vars are used in dockerfile : + The jar is included in file checker Docker image. + The spec dir could be included in the image in a future version of File Checker. + + Example: + # Explicit paths + checker = FileChecker("D:/test_checker/file_checker_exec-2.9.3.jar", "D:/test_checker/file_checker_spec") + + # Using environment variables (Docker) + checker = FileChecker() # Uses env vars + + """ + + def __init__(self, jar_path: Optional[str] = None, specs_path: Optional[str] = None): + """Initialize the File Checker. + + Args: + jar_path : Path to the File Checker .jar file. + If None -> use the FILE_CHECKER_JAR env var. + specs_path : Path to the specification (file_checker_spec) directory. + If None -> use the FILE_CHECKER_SPECS env var. + + Raises: + FileNotFoundError: If JAR or spec path don't exist + ValueError: If paths not provided and env vars not set + + """ + jar_path = jar_path or os.getenv("FILE_CHECKER_JAR") + specs_path = specs_path or os.getenv("FILE_CHECKER_SPECS") + + # checks : + if jar_path is None: + logger.error("jar_path not provided and FILE_CHECKER_JAR environment variable not defined") + raise ValueError + else: + self.jar_path = Path(jar_path) + if specs_path is None: + logger.error("jar_path not provided and FILE_CHECKER_JAR environment variable not defined") + raise ValueError + else: + self.specs_path = Path(specs_path) + + if not self.jar_path.exists(): + logger.error(f"File checker .jar file not found: {self.jar_path}") + raise FileNotFoundError + if not self.specs_path.exists(): + logger.error(f"Spec directory not found at : {self.specs_path}") + raise FileNotFoundError + + def check_files(self, files_paths_str: List[str], dac_name: str, options: list[str] = []) -> List[ValidationResult]: + """Check a list of files from a same dac using the File Checker. + + Args : + file_paths (list[str]) : list of files to checks. + ex : ['D:/data/file1.nc', 'D:/data/file2.nc', 'D:/other_data/file3.nc'] + dac_name (str) : dac name of the files : coriolis, bodc, aoml, etc. Must be the same DAC for all files. + options (list[str]) : list of file checker options. ex: ['-no-name-check'] + + Return : a list of ValidationResult objects containing the file checker results for each input files + + """ + if not files_paths_str: + logger.error("file_paths list cannot be empty") + raise ValueError + + # check if all files exist : + existing_files, missing_files = self._get_valid_files_path(files_paths_str) + if len(missing_files) > 0: + warning_msg = f"{len(missing_files)} file(s) was/were not found" + logger.warning(warning_msg) + if len(existing_files) == 0: + logger.error("No existing files were found") + raise FileNotFoundError + + # as the file checker can process a list of files from a given directory, + # we need to extract directories and files's names + # and launch files checker on each directory : + files_by_directory = self._get_filesnames_by_directory(existing_files) + + # for each directory, run the file checker on the associate list of files names : + validation_result_list = [] + for dir, files_names_list_in_dir in files_by_directory.items(): + validation_result_list.extend( + self._check_files_in_directory(dir, files_names_list_in_dir, dac_name, options) + ) + + return validation_result_list + + def _check_files_in_directory( + self, input_directory: Path, files_names: List[str], dac_name: str, options: list[str] + ) -> List[ValidationResult]: + """Run the file checker on a given directory and given files names. + + Args : + input_directory (Path) : the input directory Path + files_names (List[str]): List of files names in the directory + dac_name (str) : dac name of the files : coriolis, bodc, aoml, etc. Must be the same DAC for all files. + options (List[str]) : list of file checker options. ex: ['-no-name-check'] + + Returns : + A list of ValidationResult objects. + + """ + # need a temp directory for XML output + with tempfile.TemporaryDirectory(prefix="filechecker_output_") as temp_output_dir: + temp_output = Path(temp_output_dir) + + cmd = [ + "java", + "-jar", + str(self.jar_path), + *options, + dac_name, + str(self.specs_path), + str(temp_output), + str(input_directory), + *files_names, + ] + + # launch subprocess : + try: + result = subprocess.run(cmd, capture_output=True, text=True, check=False, timeout=300, shell=False) # nosec B603: no shell, fixed executable path + if result.stderr: + logger.error(result.stderr.strip()) + if result.stdout: + logger.info(result.stdout.strip()) + # parse xml results files + return self._parse_batch_results(temp_output, files_names) + + except subprocess.TimeoutExpired: + logger.exception("Timed out after 5 minutes") + raise RuntimeError + except Exception as e: + logger.exception("Failed to execute batch file checker") + raise RuntimeError from e + + def _parse_batch_results(self, temp_output_dir: Path, files_names: List[str]) -> List[ValidationResult]: + """Parse XML results files in the temp_ouput directory. + + For each result file build a ValidationResult and add it to the return list. + For each output file, parse the xml result and create a ValidationResult object and add it to the return list. + + Args : + temp_output (Path) : tempory folder to save XML output + input_directory (Path) : input directory path + files_names (List[str]) : list of files name that have been processed + + return : + A list of ValidationResult coming from the parsing of XML result files. + + """ + validation_results = [] + # get list of XML files : + xml_files = list(temp_output_dir.glob("*.filecheck")) + + if xml_files: + if len(xml_files) != len(files_names): + logger.warning("Unexpected number of output files") + + for xml_file in xml_files: + validation_result = self._parse_xml_output(xml_file) + if validation_result is not None: + validation_results.append(validation_result) + else: + logger.error("No results files were found") + + return validation_results + + def _parse_xml_output(self, xml_file: Path) -> ValidationResult | None: + """Parse a XML result file and build a ValidationResult object. + + Args : + xml_file (Path) : the xml file to be parsed + + Return : + an ValidationResult object + """ + try: + # Parsing XML file using defusedxml + tree: ElementTree[Element[str] | None] = DefusedET.parse(xml_file) # type: ignore[misc] + root: Element | None = tree.getroot() + + if root is None: + logger.error("Empty XML document: %s", xml_file) + return None + + def _extract_text(tag: str, default: str) -> str: + elem = root.find(tag) + if elem is not None and elem.text is not None: + return elem.text + else: + return default + + # file checker version + file_checker_version = root.attrib["filechecker_version"] + + # processed file's name + file = _extract_text("file", "") + + # result + result = _extract_text("status", "") + try: + result_enum = ResultType(result) if result else ResultType.ERROR + except ValueError: + result_enum = ResultType.ERROR + + # checking phase + phase = _extract_text("phase", "") + try: + phase_enum = PhaseType(phase) if result else PhaseType.FORMAT + except ValueError: + phase_enum = PhaseType.FORMAT + + # errors + errors_elem = root.find("errors") + if errors_elem is not None: + errors_number = errors_elem.attrib["number"] + errors_messages = list(errors_elem.itertext()) + else: + errors_number = "0" + errors_messages = [] + + # warnings + warnings_elem = root.find("warnings") + if warnings_elem is not None: + warnings_number = warnings_elem.attrib["number"] + warnings_messages = list(warnings_elem.itertext()) + else: + warnings_number = "0" + warnings_messages = [] + + validation_result = ValidationResult( + file_checker_version=file_checker_version, + file=str(file), + result=result_enum, + phase=phase_enum, + errors_number=int(errors_number), + warnings_number=int(warnings_number), + errors_messages=errors_messages, + warnings_messages=warnings_messages, + ) + + except ParseError: + logger.exception("Error when parsing file : " + str(xml_file)) + return None + + else: + return validation_result + + def _get_valid_files_path(self, files_paths_str: List[str]) -> tuple[list[Path], list[str]]: + """From a list of files, determinate for each file if it exist or not. + + Args : + files_paths_ str (list[str]) : list of files + + Return : + existing_files (List[Path]): list of existing files Path + missing_files (List[str]) : list of input files that don't exist. + """ + existing_files = [] + missing_files = [] + + for file_path_str in files_paths_str: + file_path = Path(file_path_str) + if file_path.exists(): + existing_files.append(file_path) + else: + missing_files.append(file_path_str) + + return existing_files, missing_files + + def _get_filesnames_by_directory(self, files_path: List[Path]) -> Dict[Path, List[str]]: + """Associate a source directory and list of files names from a list of files Path. + + Args : + files_path (list[Path]) : a list of files'path + + Return : + Dict[Path, List[str] : A dict with key : a directory's Path + and value : a list of files's names present in the directory. + """ + files_by_directory: Dict[Path, List[str]] = {} + for file_path in files_path: + parent_dir = file_path.parent + if parent_dir not in files_by_directory: + files_by_directory[parent_dir] = [] + files_by_directory[parent_dir].append(file_path.name) + + return files_by_directory diff --git a/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/models.py b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/models.py new file mode 100644 index 0000000..2f61af5 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/src/argofilechecker_python_wrapper/models.py @@ -0,0 +1,42 @@ +"""Module defining data models and enums for the Argo file checker validation system.""" + +from enum import Enum +from typing import List + +from pydantic import BaseModel + + +class ResultType(str, Enum): + """Error codes possibilities.""" + + SUCCESS = "FILE-ACCEPTED" + FAILURE = "FILE-REJECTED" + ERROR = "ERROR" + + +class PhaseType(str, Enum): + """File Checker verification phases.""" + + OPEN_FILE = "OPEN-FILE" + FORMAT = "FORMAT-VERIFICATION" + DATA = "DATA-VALIDATION" + NAME = "FILE-NAME-CHECK" + + +class ValidationResult(BaseModel): + """Represents the result of an Argo file checker validation.""" + + file_checker_version: str + file: str + result: ResultType + phase: PhaseType + errors_number: int + warnings_number: int + errors_messages: List[str] + warnings_messages: List[str] + + def to_string(self) -> str: + """Summary for humans.""" + status = "FILE ACCEPTED" if self.result == ResultType.SUCCESS else "FILE REJECTED" + + return f"{self.file} : {status} with {self.errors_number} error(s) and {self.warnings_number} warning(s)" diff --git a/file_checker_python/file_checker_python_wrapper/tests/conftest.py b/file_checker_python/file_checker_python_wrapper/tests/conftest.py new file mode 100644 index 0000000..d97e8c3 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/tests/conftest.py @@ -0,0 +1,90 @@ +"""Fixtures for tests suite.""" + +import os +import shutil +import subprocess +from pathlib import Path + +import pytest +import requests + + +@pytest.fixture(scope="session") +def specs_directory(tmp_path_factory) -> Path: + """Fixture which download the up-to-date specs folder from the file checker git. + + Add it to the session context for tests 'data validation' suite. + Need to provide Argo file checker github repo informations. + """ + specs_repo_url = os.getenv("SPECS_REPO_URL", "https://github.com/OneArgo/ArgoFormatChecker.git") + ref = os.getenv("SPECS_REPO_REF", "main") # branch + specs_subdir = os.getenv("TEST_REPO_SUBDIR", "file_checker_spec/") # sub folder to extract + + dest = tmp_path_factory.mktemp("specs") # session wide folder to save specs files + + _clone_subdir(specs_repo_url, ref, specs_subdir, dest) # clone repo subdir in the dest directory + + return dest + + +@pytest.fixture(scope="session") +def file_checker_jar_file(tmp_path_factory) -> Path: + """Fixture to provide the file checker executable into the session context for tests 'data validation' suite.""" + jar_download_url = os.getenv( + "JAR_URL", "https://github.com/OneArgo/ArgoFormatChecker/releases/download/v2.9.3/file_checker_exec-2.9.3.jar" + ) + + dest = tmp_path_factory.mktemp("file_checker_exec") + # download file checker JAR : + _download(jar_download_url, dest, "app.jar") + + file_path = dest / "app.jar" + + return file_path + + +def _download(url: str, dest: Path, out_file_name: str, timeout: int = 120): + """Download file from provided url. + + Arg : + url (str) : url of the file + dest (Path) : destination folder + out_file_name (str) : name of the downloaded file in the dest folder + """ + file_path = dest / "app.jar" + # dowload the jar from the provide url + with open(dest / out_file_name, "wb") as out_file: + content = requests.get(url, stream=True).content + out_file.write(content) + + if not file_path.exists(): + raise FileNotFoundError(f"File checker jar not found at {file_path}") # noqa: TRY003 + + +def _clone_subdir(repo_url: str, branch: str, subdir: str, dest: Path): + dest.parent.mkdir(parents=True, exist_ok=True) + clone_dir = dest.parent / ".clone" + if clone_dir.exists(): + shutil.rmtree(clone_dir) + + # clone git repo : + cmd_clone = ["git", "clone", "--depth=1", "--filter=blob:none", "--sparse", repo_url, str(clone_dir)] + # change branch + cmd_checkout = ["git", "-C", str(clone_dir), "checkout", branch] + # Only subdir needed : + cmd_sparse_checkout = ["git", "-C", str(clone_dir), "sparse-checkout", "set", subdir] + # launch subprocesses : + subprocess.run(cmd_clone, cwd=None, check=True) + subprocess.run(cmd_checkout, cwd=None, check=True) + subprocess.run(cmd_sparse_checkout, cwd=None, check=True) + + # move sub folder to dest : + src = clone_dir / subdir + if not src.exists(): + raise FileNotFoundError(f"Directory '{subdir}' not found in {repo_url}@{branch}") # noqa: TRY003 + if dest.exists(): + shutil.rmtree(dest) + shutil.move(str(src), str(dest)) + + # Nettoyage du clone temporaire + shutil.rmtree(clone_dir, ignore_errors=True) diff --git a/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/3901682_tech_bad_long_name.nc b/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/3901682_tech_bad_long_name.nc new file mode 100644 index 0000000000000000000000000000000000000000..d5cb74b3ff11aa0e0f702f598e57275221326fad GIT binary patch literal 279562 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 literal 0 HcmV?d00001 diff --git a/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/6990728_tech_BadUnits.nc b/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/6990728_tech_BadUnits.nc new file mode 100644 index 0000000000000000000000000000000000000000..e5fc2bc7cd42700e1945c6838176f45545426540 GIT binary patch literal 175360 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 W*R5Y)u%@UWf4vyDah7*X3j9CDF6in2 literal 0 HcmV?d00001 diff --git a/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/R6903129_088_QC0_TEMP.nc b/file_checker_python/file_checker_python_wrapper/tests/rejected_argo_data/R6903129_088_QC0_TEMP.nc new file mode 100644 index 0000000000000000000000000000000000000000..0779f7403786f0897fe856f1bba55a3fad73dd83 GIT binary patch literal 267880 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 QY;`<2W@qd%nqZ3m4|$5?F8}}l literal 0 HcmV?d00001 diff --git a/file_checker_python/file_checker_python_wrapper/tests/test_argo_data_validation.py b/file_checker_python/file_checker_python_wrapper/tests/test_argo_data_validation.py new file mode 100644 index 0000000..6adf672 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/tests/test_argo_data_validation.py @@ -0,0 +1,103 @@ +"""Validation tests on real floats data.""" + +import os +from ftplib import FTP +from pathlib import Path +from typing import List +from urllib.parse import urlparse + +import pytest + +from argofilechecker_python_wrapper import FileChecker +from argofilechecker_python_wrapper.models import ResultType, ValidationResult + + +@pytest.mark.e2e +@pytest.mark.parametrize( + "float_number,dac_name", + [("2903996", "coriolis"), ("5900177", "bodc"), ("1900360", "aoml"), ("6990538", "coriolis"), ("4901791", "meds")], +) # noqa: E501 +def test_files_from_gdac_should_be_accepted(float_number, dac_name, tmp_path, specs_directory, file_checker_jar_file): + """Argo netcdf files from GDAC should be accepted.""" + # first download relevant files in temp directory : + ftp_url = os.getenv("GDAC_FTP_HOST", "ftp://ftp.ifremer.fr/ifremer/argo/dac") + dest_folder = tmp_path / float_number + dest_folder.mkdir() + _download_relevant_files_from_gdac_ftp(ftp_url, dac_name, float_number, dest_folder) + + # run file checker on each file and expect to have only accepted files + # Files come from GDAC and should be accepted by file checker + list_files = [f"{dest_folder}/{file}" for file in os.listdir(dest_folder)] + file_checker = FileChecker(file_checker_jar_file, specs_directory) + + results: List[ValidationResult] = file_checker.check_files(list_files, dac_name) + # check if all files have been processed + assert len(list_files) == len(results) + # check if all files are ACCEPTED (which is the expected result for GDAC files) + failures = [r.file for r in results if r.result != ResultType.SUCCESS] + assert not failures, f"REJECTED detected: {failures}" + + +@pytest.mark.e2e +def test_bad_argo_netcdf_should_be_rejected(specs_directory, file_checker_jar_file): + """Bad formatted argo netcdf should be rejected.""" + # files in local 'rejected_argo_data' folder : + test_dir = Path(__file__).parent + rejected_dir = test_dir / "rejected_argo_data" + list_files = [str(rejected_dir / file) for file in os.listdir(rejected_dir)] + # run file checker : + file_checker = FileChecker(file_checker_jar_file, specs_directory) + results: List[ValidationResult] = file_checker.check_files(list_files, "coriolis", ["-no-name-check"]) + # check if all files have been processed + assert len(list_files) == len(results) + # check if all files are REJECTED + success = [r.file for r in results if r.result == ResultType.SUCCESS] + assert not success, f"ACCEPTED detected: {success}" + + +def _download_relevant_files_from_gdac_ftp(ftp_url: str, dac_name: str, float_number: str, dest: Path): + """Download from a ftp server the different files (tech, meta, traj, profiles) for a specified dac and float number. + + Args : + ftp_url (str) : root directory where dac directories are found + dac_name (str) + float_number (str) + """ + # parse url to retrieve host and path + float_ftp_url = f"{ftp_url}/{dac_name}/{float_number}" + parsed_url = urlparse(float_ftp_url) + hostname = parsed_url.hostname + path = parsed_url.path + + # connect to ftp + if hostname is not None: + ftp = FTP(hostname) + ftp.login() + # go to the right folder : + ftp.cwd(path) + # download meta, traj and tech files : + meta_tech_traj_files_list = [f"{float_number}_Rtraj.nc", f"{float_number}_tech.nc", f"{float_number}_meta.nc"] + _download_files_from_ftp(ftp, meta_tech_traj_files_list, dest) + + # dowload profiles files : + ftp.cwd("profiles") + profiles_files_names = ftp.nlst() + # exclude Synthetic profiles (first letters is 'S') which are not checked by fileChecker + profiles_files_names_without_synth = [f for f in profiles_files_names if not f.startswith("S")] + _download_files_from_ftp(ftp, profiles_files_names_without_synth, dest) + + ftp.quit() + + +def _download_files_from_ftp(ftp, files_names_list, dest): + """Download a list of files to a dest directory from a FTP connexion. + + Args : + ftp (FTP) : FTP object (ftplib) connected to the right directory + files_names_list (List[str]) : list of file names present in the ftp directory + dest (Path) : Path of the directory to download files + """ + for file_name in files_names_list: + if file_name in ftp.nlst(): + with open(dest / file_name, "wb") as fp: + ftp.retrbinary(f"RETR {file_name}", fp.write) diff --git a/file_checker_python/file_checker_python_wrapper/tests/test_filechecker.py b/file_checker_python/file_checker_python_wrapper/tests/test_filechecker.py new file mode 100644 index 0000000..c57c8ba --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/tests/test_filechecker.py @@ -0,0 +1,34 @@ +"""Tests for the argofilechecker_python_wrapper module.""" + +import pytest + +from argofilechecker_python_wrapper import FileChecker + + +@pytest.fixture +def env_paths(tmp_path, monkeypatch): + """Create a mock JAR file and specs dir and add it to env variables.""" + jar = tmp_path / "app.jar" + jar.touch() # simulate jar existence + specs = tmp_path / "specs" + specs.mkdir() + + monkeypatch.setenv("FILE_CHECKER_JAR", str(jar)) + monkeypatch.setenv("FILE_CHECKER_SPECS", str(specs)) + return jar, specs + + +def test_check_files_empty_input_files_list(env_paths): + """Should raise an Error when no files list are provided.""" + file_checker = FileChecker() + + with pytest.raises(ValueError): + file_checker.check_files([], "coriolis") + + +def test_check_files_all_missing_raise(env_paths): + """Should raise an error when a file provided doesn't exists.""" + file_checker = FileChecker() + + with pytest.raises(FileNotFoundError): + file_checker.check_files(["NOEXISTS.nc"], "coriolis") diff --git a/file_checker_python/file_checker_python_wrapper/tox.ini b/file_checker_python/file_checker_python_wrapper/tox.ini new file mode 100644 index 0000000..43fcc05 --- /dev/null +++ b/file_checker_python/file_checker_python_wrapper/tox.ini @@ -0,0 +1,64 @@ +[base] +# Name of the Python package we're going to run jobs against +name = argofilechecker_python_wrapper + +[tox] +minversion = 4.23.2 + +# Use Python as provided by our environment. +ignore_basepython_conflict = true + +# Which envs to run when Tox is called with no args. +envlist = test, test_e2e, build, lint, bandit, type + +[testenv:test] +setenv = PYTHONPATH = {toxinidir}/src +# Our primary base environment for all jobs. +extras = test +allowlist_externals = + coverage + pytest +commands = + coverage run -m --source {[base]name} --data-file=coverage_reports/.coverage --omit tests/* pytest -m "not e2e" + coverage xml --data-file=coverage_reports/.coverage -o coverage_reports/coverage.xml + coverage report --data-file=coverage_reports/.coverage -m + +[testenv:test_e2e] +description = end-to-end tests downloading data from GDAC +setenv = PYTHONPATH = {toxinidir}/src +extras = test +allowlist_externals = + pytest +commands = + pytest -m "e2e" -s + +[testenv:lint] +# Linting with Ruff. +allowlist_externals = ruff +extras = lint +commands = + ruff check --fix src/{[base]name} + +[testenv:bandit] +# Security checks with bandit. +allowlist_externals = bandit +extras = bandit +commands = + bandit -r src/{[base]name} -c pyproject.toml + +[testenv:type] +# Type-checking with Mypy. +allowlist_externals = mypy +extras = type +commands = + mypy src/{[base]name} + +[testenv:build] +# Package building with Poetry and Twine. +allowlist_externals = + poetry + twine +extras = build +commands = + poetry build + twine check dist/* diff --git a/python.Dockerfile b/python.Dockerfile new file mode 100644 index 0000000..dcdf627 --- /dev/null +++ b/python.Dockerfile @@ -0,0 +1,108 @@ +FROM ghcr.io/oneargo/argoformatchecker/app:develop AS base + +USER root + +# Install Poetry for dependency management. +ENV POETRY_HOME=/opt/poetry +ENV PATH="${POETRY_HOME}/bin:${PATH}" + +RUN \ + apk add --no-cache \ + python3 \ + py3-pip \ + curl \ + build-base \ + python3-dev \ + git && \ + ln -sf /usr/bin/python3 /usr/bin/python && \ + mkdir -p /opt/poetry/project /opt/poetry/bin && \ + curl -sSL https://install.python-poetry.org | python - + +# Install dependencies. +COPY file_checker_python/file_checker_python_wrapper/pyproject.toml file_checker_python/file_checker_python_wrapper/poetry*.lock file_checker_python/file_checker_python_wrapper/README.md /opt/poetry/dep/ +RUN \ + cd /opt/poetry/dep && \ + poetry config virtualenvs.create false && \ + if [ ! -f poetry.lock ]; then poetry lock; fi && \ + poetry install --no-root && \ + poetry env info + +FROM base AS build-package +# Ephemeral environment for building packages. +RUN --mount=type=bind,source=./file_checker_python/file_checker_python_wrapper,target=/opt/dep,rw=true \ + cd /opt/dep && \ + rm -rf ./dist && \ + POETRY_DYNAMIC_VERSIONING_BYPASS=1.0.0 poetry build && \ + mkdir /opt/build && \ + mv ./dist/*.whl /opt/build + +FROM base AS file-checker-python + +LABEL org.opencontainers.image.authors="yvan.lubac@euro-argo.eu" +LABEL org.opencontainers.image.description="Docker image for Argo File Checker Python Wrapper" +LABEL org.opencontainers.image.url="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" +LABEL org.opencontainers.image.source="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" +LABEL org.opencontainers.image.documentation="https://github.com/British-Oceanographic-Data-Centre/amrit-repos/wiki" +LABEL org.opencontainers.image.licenses="TBD" +LABEL org.opencontainers.image.vendor="Advance Marine Research Infrastructures Together (AMRIT)" + +COPY ./file_checker_spec /app/specs + +#env variables for file checker +ENV FILE_CHECKER_JAR="/app/app.jar" +ENV FILE_CHECKER_SPECS="/app/specs" + +RUN --mount=type=bind,from=build-package,source=/opt/build,target=/opt/build \ + python -m venv /opt/venv && \ + /opt/venv/bin/pip install /opt/build/*.whl && \ + /opt/venv/bin/python -c "from argofilechecker_python_wrapper import FileChecker; print('OK')" + + +ENV PATH="/opt/venv/bin:${PATH}" + +WORKDIR /home/app + +USER fileCheckerRunner + +#overide entrypoint from base image +ENTRYPOINT ["/opt/venv/bin/python"] + +FROM base AS file-checker-api + +LABEL org.opencontainers.image.description="Docker image for Argo File Checker Python API" +LABEL org.opencontainers.image.url="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" +LABEL org.opencontainers.image.source="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" + +COPY ./file_checker_spec /app/specs + +#env variables for file checker +ENV FILE_CHECKER_JAR="/app/app.jar" +ENV FILE_CHECKER_SPECS="/app/specs" +ENV UPLOAD_FILES_DIR="/home/app/input" + +WORKDIR /home/app +COPY file_checker_python/file_checker_python_api/pyproject.toml file_checker_python/file_checker_python_api/poetry*.lock file_checker_python/file_checker_python_api/README.md ./ + +RUN --mount=type=bind,from=build-package,source=/opt/build,target=/opt/build \ + python -m venv /opt/venv && \ + /opt/venv/bin/pip install /opt/build/*.whl && \ + /opt/venv/bin/python -c "from argofilechecker_python_wrapper import FileChecker; print('OK')" + +RUN --mount=type=bind,from=build-package,source=/opt/build,target=/opt/build \ + poetry config virtualenvs.create false && \ + poetry add /opt/build/*.whl && \ + if [ ! -f poetry.lock ]; then poetry lock; fi && \ + poetry install --no-root && \ + poetry env info + +COPY file_checker_python/file_checker_python_api/ ./ + +ENV PATH="/opt/venv/bin:${PATH}" +RUN mkdir /home/app/input +RUN chown fileCheckerRunner:gcontainer /home/app/input + +USER fileCheckerRunner + +#overide entrypoint from base image +ENTRYPOINT ["poetry"] +CMD ["run", "gunicorn", "file_checker_api:app", "-b", "0.0.0.0:8000", "-k", "uvicorn.workers.UvicornWorker", "--timeout", "300"] diff --git a/python.README.md b/python.README.md new file mode 100644 index 0000000..cd4cb06 --- /dev/null +++ b/python.README.md @@ -0,0 +1,92 @@ +# ArgoFileChecker Python Wrapper + +A lightweight Python wrapper around the **Argo NetCDF File Checker**. +It runs the File Checker JAR as a **subprocess**, parses the generated XML output files (which are generated in a temporary folder), and returns typed `ValidationResult` objects. + +## Installation + +### With Poetry + +```bash +poetry add argofilechecker-python-wrapper +``` + +## Run ArgoFileChecker Python Wrapper (after installing the package and any additional dependencies) +The wrapper can receive paths explicitly or through environment variables: + +FILE_CHECKER_JAR: path to file_checker_exec-*.jar + +FILE_CHECKER_SPECS: path to the file_checker_spec directory + +### Usage example +See /demo_scripts where a demo python script is provided along with a file checker .jar and some netcdf test data. + +```bash +cd ./demo_scripts +poetry run python demo_test.py +``` + +## Run ArgoFileChecker Python Wrapper in a pre-built container image + +### build and run the image + +```bash +docker build --target file-checker-python -f python.Dockerfile -t argofilechecker-python:latest . +``` + +Argo File checker .jar file will be included in the docker image but you still need to mount your data and specs volumes and also your script file (if not used in interactive mode) : + +```bash +docker run --rm -v ${pwd}/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py:/scripts/demo_docker.py -v ${pwd}/demo/inputs/2903996:/data argofilechecker-python:latest /scripts/demo_docker.py +``` +Ensure that the correct volumes names are used in your script. + +You can use interactive mode to execute python code inside the container : + +```bash +docker run --rm -it -v ${pwd}/demo/inputs/2903996:/data argofilechecker-python:latest +>>> from argofilechecker_python_wrapper import FileChecker +>>> filechecker = FileChecker(specs_path='/app/specs') +>>> results = filechecker.check_files(['/data/2903996_meta.nc'],"coriolis") +>>> results[0].to_string() +'/data/2903996_meta.nc : FILE ACCEPTED with 0 error(s) and 0 warning(s)' +``` + + +### Results Values + +- ResultType.SUCCESS → the file is accepted by the File Checker. + +- ResultType.FAILURE → the file is rejected (errors found). + +- ResultType.ERROR → internal error in the checker or parsing failure. + +The phase (PhaseType) indicates the stage where the error occurred: opening, format check, data validation, or file name check. + +Errors and warnings's number and messages can be accessed also. + +For more information see models.py + +# Argo File Checker Python API + +A FastAPI app providing an endpoint to access file checker functionality via the /check-files endpoint. + +## Build and run using Docker + +```bash +docker build --target file-checker-api -f python.Dockerfile -t argofilechecker-api:latest . +docker run -p 8000:8000 argofilechecker-api:latest +``` + +The file checker endpoint will then be available on http://localhost:8000/check-files +API documentation can be found on http://localhost:8000/docs + +The DAC for the files needs to be specified as a parameter. The files to check need to be included in the body of a `multipart/form-data` type request, e.g.: +For example, post an example file found in the _argofilechecker-python-wrapper/demo_scripts/test_data/2903996_ folder to `http://localhost:8000/check-files?dac=coriolis` +```http request +curl -X 'POST' \ + 'http://localhost:8000/check-files?dac=coriolis' \ + -H 'accept: application/json' \ + -H 'Content-Type: multipart/form-data' \ + -F 'files=@2903996_meta.nc' +``` From 2aa9c3f9911dd48172b9de7b5aa972170b5e7cc7 Mon Sep 17 00:00:00 2001 From: LUBAC Date: Wed, 1 Oct 2025 10:09:34 +0200 Subject: [PATCH 2/6] update readme --- README.md | 9 ++++++--- python.README.md | 7 ++++--- 2 files changed, 10 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0403056..993093c 100644 --- a/README.md +++ b/README.md @@ -34,7 +34,7 @@ docker run --rm -v [ABSOLUTE_PATH_TO_SPEC]:/app/file_checker_spec -v [ABSOLUTE_P You need to mount external directories to the container : -[ABSOLUTE_PATH_TO_SPEC] : the file_checker_spec directory path. +[ABSOLUTE_PATH_TO_SPEC] : OPTIONAL - The file_checker_spec directory path (if you don't want to use the specs included in the docker container). [ABSOLUTE_PATH_TO_DATA_FOLDER] : Path to directory containing the argo necdf files to be checked. The fileChecker will not seek files in subfolders @@ -43,7 +43,7 @@ You need to mount external directories to the container : Example : ```bash -docker run --rm -v D:\test_file_checker\file_checker_spec:/app/file_checker_spec -v D:\test_file_checker\datatest:/app/data -v D:\test_file_checker\results:/app/results ghcr.io/oneargo/argoformatchecker/app:develop -no-name-check coriolis ./file_checker_spec ./results ./data +docker run --rm -v D:\test_file_checker\datatest:/app/data -v D:\test_file_checker\results:/app/results ghcr.io/oneargo/argoformatchecker/app:develop -no-name-check coriolis ./file_checker_spec ./results ./data ``` ### Run the application using Docker Compose @@ -73,7 +73,6 @@ FILECHECKER_IMAGE=ghcr.io/oneargo/argoformatchecker/app FILECHECKER_IMAGE_TAG=develop # External directories to mount to the container -FILECHECKER_SPEC_VOLUME='D:\test_compose\file_checker_spec' FILECHECKER_INPUT_VOLUME='D:\test_compose\data' FILECHECKER_OUTPUT_VOLUME='D:\test_compose\results' @@ -107,6 +106,10 @@ or for Windows : output files will be generated in `./demo/outputs`. +### Run File checker using Python and an API + +In folder /file-checker-python you will find a python wrapper and an API to facilitate the use of Argo FileChecker. See python.README for more informations. + ### Test data To further test the Argo File Checker, you will find argo data here : https://www.argodatamgt.org/DataAccess.html diff --git a/python.README.md b/python.README.md index cd4cb06..e79a30d 100644 --- a/python.README.md +++ b/python.README.md @@ -8,7 +8,8 @@ It runs the File Checker JAR as a **subprocess**, parses the generated XML outpu ### With Poetry ```bash -poetry add argofilechecker-python-wrapper +cd ./file_checker_python/argofilechecker-python-wrapper +poetry install ``` ## Run ArgoFileChecker Python Wrapper (after installing the package and any additional dependencies) @@ -34,7 +35,7 @@ poetry run python demo_test.py docker build --target file-checker-python -f python.Dockerfile -t argofilechecker-python:latest . ``` -Argo File checker .jar file will be included in the docker image but you still need to mount your data and specs volumes and also your script file (if not used in interactive mode) : +Argo File checker .jar file will be included in the docker image but you still need to mount your data your script file (if not used in interactive mode) : ```bash docker run --rm -v ${pwd}/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py:/scripts/demo_docker.py -v ${pwd}/demo/inputs/2903996:/data argofilechecker-python:latest /scripts/demo_docker.py @@ -46,7 +47,7 @@ You can use interactive mode to execute python code inside the container : ```bash docker run --rm -it -v ${pwd}/demo/inputs/2903996:/data argofilechecker-python:latest >>> from argofilechecker_python_wrapper import FileChecker ->>> filechecker = FileChecker(specs_path='/app/specs') +>>> filechecker = FileChecker() >>> results = filechecker.check_files(['/data/2903996_meta.nc'],"coriolis") >>> results[0].to_string() '/data/2903996_meta.nc : FILE ACCEPTED with 0 error(s) and 0 warning(s)' From 4a645ed86962aed820f6e610303fbeb55dea5775 Mon Sep 17 00:00:00 2001 From: LUBAC Date: Wed, 1 Oct 2025 10:10:14 +0200 Subject: [PATCH 3/6] update demo_docker --- .../file_checker_python_wrapper/demo_scripts/demo_docker.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py index 2abefc4..d6e8b02 100644 --- a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py +++ b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py @@ -6,8 +6,6 @@ from argofilechecker_python_wrapper import FileChecker, ValidationResult from argofilechecker_python_wrapper.models import ResultType -specs_path = "/app/specs" - # 1) Instantiate the wrapper (explicit paths). # file checker jar is already contained in the docker image From 734554a3208278b9e429e692f67f262e95609492 Mon Sep 17 00:00:00 2001 From: LUBAC Date: Wed, 1 Oct 2025 10:13:51 +0200 Subject: [PATCH 4/6] update file checker docker compose demo --- .env.demo.bodc | 1 - .env.demo.coriolis | 1 - .env.docs | 1 - compose.yaml | 3 +-- 4 files changed, 1 insertion(+), 5 deletions(-) diff --git a/.env.demo.bodc b/.env.demo.bodc index 6c0dcda..059bf1e 100644 --- a/.env.demo.bodc +++ b/.env.demo.bodc @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop #availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest # External directories to mount to the container -FILECHECKER_SPEC_VOLUME=./file_checker_spec FILECHECKER_INPUT_VOLUME=./demo/inputs/3901945 FILECHECKER_OUTPUT_VOLUME=./demo/outputs/3901945 diff --git a/.env.demo.coriolis b/.env.demo.coriolis index 02c5783..4ea5980 100644 --- a/.env.demo.coriolis +++ b/.env.demo.coriolis @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop #availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest # External directories to mount to the container -FILECHECKER_SPEC_VOLUME=./file_checker_spec FILECHECKER_INPUT_VOLUME=./demo/inputs/2903996 FILECHECKER_OUTPUT_VOLUME=./demo/outputs/2903996 diff --git a/.env.docs b/.env.docs index 1c793b6..b660a54 100644 --- a/.env.docs +++ b/.env.docs @@ -4,7 +4,6 @@ FILECHECKER_IMAGE_TAG=develop #availables tags at https://github.com/OneArgo/ArgoFormatChecker/tags + develop + latest # External directories to mount to the container -FILECHECKER_SPEC_VOLUME= FILECHECKER_INPUT_VOLUME= FILECHECKER_OUTPUT_VOLUME= diff --git a/compose.yaml b/compose.yaml index 4a71e93..1d03d2c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -5,8 +5,7 @@ services: user: "${DOCKER_UID:-0}:${DOCKER_GID:-0}" group_add: - 1001 - volumes: - - ${FILECHECKER_SPEC_VOLUME}:/app/file_checker_spec:ro + volumes: - ${FILECHECKER_INPUT_VOLUME}:/app/data:ro - ${FILECHECKER_OUTPUT_VOLUME}:/app/results:rw command: ${FILECHECKER_OPTIONS} ${DAC_NAME} ./file_checker_spec ./results ./data ${FILES_NAMES} \ No newline at end of file From dbc46991ac2b6909aa54929b2558527de9842438 Mon Sep 17 00:00:00 2001 From: LUBAC Date: Wed, 1 Oct 2025 10:31:52 +0200 Subject: [PATCH 5/6] update dockerfile and fix demo_docker --- .../file_checker_python_wrapper/README.md | 70 ------------------- .../demo_scripts/demo_docker.py | 2 +- python.Dockerfile | 6 +- 3 files changed, 3 insertions(+), 75 deletions(-) diff --git a/file_checker_python/file_checker_python_wrapper/README.md b/file_checker_python/file_checker_python_wrapper/README.md index 7794933..e69de29 100644 --- a/file_checker_python/file_checker_python_wrapper/README.md +++ b/file_checker_python/file_checker_python_wrapper/README.md @@ -1,70 +0,0 @@ -# ArgoFileChecker Python Wrapper - -A lightweight Python wrapper around the **Argo NetCDF File Checker**. -It runs the File Checker JAR as a **subprocess**, parses the generated XML output files (which are generated in a temporary folder), and returns typed `ValidationResult` objects. - -## Installation - -### With Poetry - -```bash -poetry add argofilechecker-python-wrapper -``` - -## Run ArgoFileChecker Python Wrapper (after installing the package and any additional dependencies) -The wrapper can receive paths explicitly or through environment variables: - -FILE_CHECKER_JAR: path to file_checker_exec-*.jar - -FILE_CHECKER_SPECS: path to the file_checker_spec directory - -### Usage example -See /demo_scripts where a demo python script is provided along with a file checker .jar and some netcdf test data. - -```bash -cd ./demo_scripts -poetry run python demo_test.py -``` - -## Run ArgoFileChecker Python Wrapper in a pre-built container image - -### build and run the image - -```bash -docker build -t argofilechecker-python:latest . -``` - -Argo File checker .jar file will be included in the docker image but you still need to mount your data and specs volumes and also your script file (if not used in interactive mode) : - -```bash -cd ./demo_scripts -docker run --rm -v ${pwd}/demo_docker.py:/scripts/demo_docker.py -v ${pwd}/test_data/2903996:/data -v ${pwd}/file_checker_spec:/specs argofilechecker-python:latest /scripts/demo_docker.py -``` -Ensure that the correct volumes names are used in your script. - -You can use interactive mode to execute python code inside the container : - -```bash -cd ./demo_scripts -docker run --rm -it -v ${pwd}/test_data/2903996:/data -v ${pwd}/file_checker_spec:/specs argofilechecker-python:latest ->>> from argofilechecker_python_wrapper import FileChecker ->>> filechecker = FileChecker(specs_path='/specs') ->>> results = filechecker.check_files(['/data/2903996_meta.nc'],"coriolis") ->>> results[0].to_string() -'/data/2903996_meta.nc : FILE ACCEPTED with 0 error(s) and 0 warning(s)' -``` - - -### Results Values - -- ResultType.SUCCESS → the file is accepted by the File Checker. - -- ResultType.FAILURE → the file is rejected (errors found). - -- ResultType.ERROR → internal error in the checker or parsing failure. - -The phase (PhaseType) indicates the stage where the error occurred: opening, format check, data validation, or file name check. - -Errors and warnings's number and messages can be accessed also. - -For more information see models.py \ No newline at end of file diff --git a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py index d6e8b02..1af6701 100644 --- a/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py +++ b/file_checker_python/file_checker_python_wrapper/demo_scripts/demo_docker.py @@ -9,7 +9,7 @@ # 1) Instantiate the wrapper (explicit paths). # file checker jar is already contained in the docker image -file_checker = FileChecker(specs_path=specs_path) +file_checker = FileChecker() # 2) Validate a list of files from the same DAC diff --git a/python.Dockerfile b/python.Dockerfile index dcdf627..0ab8fc9 100644 --- a/python.Dockerfile +++ b/python.Dockerfile @@ -50,7 +50,7 @@ COPY ./file_checker_spec /app/specs #env variables for file checker ENV FILE_CHECKER_JAR="/app/app.jar" -ENV FILE_CHECKER_SPECS="/app/specs" +ENV FILE_CHECKER_SPECS="/app/file_checker_spec" RUN --mount=type=bind,from=build-package,source=/opt/build,target=/opt/build \ python -m venv /opt/venv && \ @@ -73,11 +73,9 @@ LABEL org.opencontainers.image.description="Docker image for Argo File Checker P LABEL org.opencontainers.image.url="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" LABEL org.opencontainers.image.source="https://github.com/British-Oceanographic-Data-Centre/amrit-repos" -COPY ./file_checker_spec /app/specs - #env variables for file checker ENV FILE_CHECKER_JAR="/app/app.jar" -ENV FILE_CHECKER_SPECS="/app/specs" +ENV FILE_CHECKER_SPECS="/app/file_checker_spec" ENV UPLOAD_FILES_DIR="/home/app/input" WORKDIR /home/app From b45d5d77f308657127dd51e2d4fb8e30e1b26ca1 Mon Sep 17 00:00:00 2001 From: LUBAC Date: Wed, 1 Oct 2025 11:03:15 +0200 Subject: [PATCH 6/6] fix readme --- python.README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python.README.md b/python.README.md index e79a30d..87898b2 100644 --- a/python.README.md +++ b/python.README.md @@ -8,7 +8,7 @@ It runs the File Checker JAR as a **subprocess**, parses the generated XML outpu ### With Poetry ```bash -cd ./file_checker_python/argofilechecker-python-wrapper +cd ./file_checker_python/file_checker_python_wrapper poetry install ```