From 14629469755149fc0936c0bcc31c778dee36865e Mon Sep 17 00:00:00 2001 From: davidhallam4-nhs <110543996+davidhallam4-nhs@users.noreply.github.com> Date: Wed, 30 Jul 2025 11:05:08 +0100 Subject: [PATCH 1/5] MESH-2092 remove python 3.7 and 3.8 as EOL, added 3.12 and 3.13 into the mix and fix endpoint tests following Spine's migrations --- .github/workflows/merge-develop.yml | 6 +- .github/workflows/merge-release.yml | 4 +- .github/workflows/pull-request.yml | 18 +- .tool-versions | 4 +- CONTRIBUTING.md | 10 +- Makefile | 4 +- README.md | 2 +- SECURITY.md | 4 +- docker-compose.yml | 2 +- mesh_client/__init__.py | 3 +- poetry.lock | 1401 +++++++++++---------- pyproject.toml | 20 +- setup.py | 4 +- sonar-project.properties | 2 +- tests/helpers.py | 7 +- tests/mesh_endpoint_connectivity_tests.py | 236 ++-- 16 files changed, 919 insertions(+), 808 deletions(-) diff --git a/.github/workflows/merge-develop.yml b/.github/workflows/merge-develop.yml index d954268..7b8c8cc 100644 --- a/.github/workflows/merge-develop.yml +++ b/.github/workflows/merge-develop.yml @@ -18,12 +18,12 @@ jobs: - name: setup python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version-file: 'pyproject.toml' - name: setup poetry uses: abatilo/actions-poetry@v3 with: - poetry-version: 1.8.3 + poetry-version: 2.1.3 - name: add poetry plugins run: | @@ -34,7 +34,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.8-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard diff --git a/.github/workflows/merge-release.yml b/.github/workflows/merge-release.yml index 1c58ebe..32ba33f 100644 --- a/.github/workflows/merge-release.yml +++ b/.github/workflows/merge-release.yml @@ -23,12 +23,12 @@ jobs: - name: setup python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version-file: 'pyproject.toml' - name: setup poetry uses: abatilo/actions-poetry@v3 with: - poetry-version: 1.8.3 + poetry-version: 2.1.3 - name: add poetry plugins run: | diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 13765b0..d726a20 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -9,7 +9,7 @@ jobs: tox: strategy: matrix: - python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] runs-on: ubuntu-latest if: github.repository == 'NHSDigital/mesh-client' @@ -95,12 +95,12 @@ jobs: - name: setup python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version-file: 'pyproject.toml' - name: setup poetry uses: abatilo/actions-poetry@v3 with: - poetry-version: 1.8.3 + poetry-version: 2.1.3 - name: add poetry plugins run: | @@ -111,7 +111,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.8-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard @@ -213,12 +213,12 @@ jobs: - name: setup python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version-file: 'pyproject.toml' - name: setup poetry uses: abatilo/actions-poetry@v3 with: - poetry-version: 1.8.3 + poetry-version: 2.1.3 - name: add poetry plugins run: | @@ -229,7 +229,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.8-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard @@ -298,12 +298,12 @@ jobs: - name: setup python uses: actions/setup-python@v5 with: - python-version: "3.8" + python-version-file: 'pyproject.toml' - name: setup poetry uses: abatilo/actions-poetry@v3 with: - poetry-version: 1.8.3 + poetry-version: 2.1.3 - name: add poetry plugins run: | diff --git a/.tool-versions b/.tool-versions index 23e4b1f..34b3b60 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ -poetry 1.8.3 -python 3.10.12 3.9.13 3.7.12 3.8.14 3.11.4 +poetry 2.1.3 +python 3.10.18 3.9.23 3.11.13 3.12.11 3.13.5 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2b90fd4..d42765b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -102,12 +102,4 @@ You can check for secrets / test patterns at any time though with ```shell make check-secrets-all -``` - -## Supporting multiple versions of dependencies - -Currently we still support version python 3.7 for the mesh-client but as some packages now have vulnerabilities that are only fixed in higher versions of python we must support multiple versions of the packages. As we use setuptools we have a defined way of doing this in `setup.py` which means packages in the `pyproject.toml` for multiple versions should be defined as a list of dictionaries with the keys of `version` and `markers` as so: - -```toml -requests = [{version = ">=2.26.0", markers = "python_version<'3.8'"},{version = ">=2.32.0", markers = "python_version>='3.8'"}] -``` +``` \ No newline at end of file diff --git a/Makefile b/Makefile index 5644914..c022c72 100644 --- a/Makefile +++ b/Makefile @@ -49,10 +49,10 @@ delete-hooks: refresh-hooks: delete-hooks .git/hooks/pre-commit .git/hooks/commit-msg install: - poetry install --sync + poetry sync install-ci: - poetry install --without local --sync + poetry sync --without local update: poetry update diff --git a/README.md b/README.md index 7d0d0ed..232525e 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ MESH Client =========== -A Python client for [NHS Digital's MESH API](https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api). +A Python client for [NHS England's MESH API](https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api). Release Notes ------------ diff --git a/SECURITY.md b/SECURITY.md index fb74718..6cea862 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,6 +1,6 @@ # Security -NHS Digital takes security and the protection of private data extremely +NHS England takes security and the protection of private data extremely seriously. If you believe you have found a vulnerability or other issue which has compromised or could compromise the security of any of our systems and/or private data managed by our systems, please do not hesitate to contact us using @@ -25,7 +25,7 @@ Programme, you can report directly to us at: https://hackerone.com/nhs ### NCSC You can send your report to the National Cyber Security Centre, who will assess -your report and pass it on to NHS Digital if necessary. +your report and pass it on to NHS England if necessary. You can report vulnerabilities here: https://www.ncsc.gov.uk/information/vulnerability-reporting diff --git a/docker-compose.yml b/docker-compose.yml index c718a19..5a3c5af 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,7 +4,7 @@ services: mesh_sandbox: build: - context: https://github.com/NHSDigital/mesh-sandbox.git#refs/tags/v1.0.13 + context: https://github.com/NHSDigital/mesh-sandbox.git#refs/tags/v1.0.27 ports: - "8701:443" deploy: diff --git a/mesh_client/__init__.py b/mesh_client/__init__.py index 950380b..d8693fc 100644 --- a/mesh_client/__init__.py +++ b/mesh_client/__init__.py @@ -10,12 +10,13 @@ import sys import uuid import warnings +from collections.abc import Generator from dataclasses import dataclass from hashlib import sha256 from io import BytesIO from itertools import chain from types import TracebackType -from typing import Any, Dict, Generator, List, NoReturn, Optional, Tuple, Type, TypeVar, Union, cast +from typing import Any, Dict, List, NoReturn, Optional, Tuple, Type, TypeVar, Union, cast from urllib.parse import quote as q from urllib.parse import urlparse diff --git a/poetry.lock b/poetry.lock index 2fa612f..7daaec8 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,102 +1,52 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "asttokens" -version = "2.4.1" +version = "3.0.0" description = "Annotate AST trees with source code positions" optional = false -python-versions = "*" +python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "asttokens-2.4.1-py2.py3-none-any.whl", hash = "sha256:051ed49c3dcae8913ea7cd08e46a606dba30b79993209636c4875bc1d637bc24"}, - {file = "asttokens-2.4.1.tar.gz", hash = "sha256:b03869718ba9a6eb027e134bfdf69f38a236d681c83c160d510768af11254ba0"}, + {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, + {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, ] -[package.dependencies] -six = ">=1.12.0" - [package.extras] -astroid = ["astroid (>=1,<2)", "astroid (>=2,<4)"] -test = ["astroid (>=1,<2)", "astroid (>=2,<4)", "pytest"] +astroid = ["astroid (>=2,<4)"] +test = ["astroid (>=2,<4)", "pytest", "pytest-cov", "pytest-xdist"] [[package]] name = "black" -version = "23.3.0" +version = "25.1.0" description = "The uncompromising code formatter." optional = false -python-versions = ">=3.7" -files = [ - {file = "black-23.3.0-cp310-cp310-macosx_10_16_arm64.whl", hash = "sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_universal2.whl", hash = "sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9"}, - {file = "black-23.3.0-cp310-cp310-macosx_10_16_x86_64.whl", hash = "sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2"}, - {file = "black-23.3.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c"}, - {file = "black-23.3.0-cp310-cp310-win_amd64.whl", hash = "sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_arm64.whl", hash = "sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_universal2.whl", hash = "sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b"}, - {file = "black-23.3.0-cp311-cp311-macosx_10_16_x86_64.whl", hash = "sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d"}, - {file = "black-23.3.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70"}, - {file = "black-23.3.0-cp311-cp311-win_amd64.whl", hash = "sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326"}, - {file = "black-23.3.0-cp37-cp37m-macosx_10_16_x86_64.whl", hash = "sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b"}, - {file = "black-23.3.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2"}, - {file = "black-23.3.0-cp37-cp37m-win_amd64.whl", hash = "sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_arm64.whl", hash = "sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_universal2.whl", hash = "sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331"}, - {file = "black-23.3.0-cp38-cp38-macosx_10_16_x86_64.whl", hash = "sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5"}, - {file = "black-23.3.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961"}, - {file = "black-23.3.0-cp38-cp38-win_amd64.whl", hash = "sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_arm64.whl", hash = "sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_universal2.whl", hash = "sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3"}, - {file = "black-23.3.0-cp39-cp39-macosx_10_16_x86_64.whl", hash = "sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266"}, - {file = "black-23.3.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab"}, - {file = "black-23.3.0-cp39-cp39-win_amd64.whl", hash = "sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb"}, - {file = "black-23.3.0-py3-none-any.whl", hash = "sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4"}, - {file = "black-23.3.0.tar.gz", hash = "sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940"}, -] - -[package.dependencies] -click = ">=8.0.0" -mypy-extensions = ">=0.4.3" -packaging = ">=22.0" -pathspec = ">=0.9.0" -platformdirs = ">=2" -tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.2", markers = "python_version < \"3.8\" and implementation_name == \"cpython\""} -typing-extensions = {version = ">=3.10.0.0", markers = "python_version < \"3.10\""} - -[package.extras] -colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)"] -jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] -uvloop = ["uvloop (>=0.15.2)"] - -[[package]] -name = "black" -version = "24.8.0" -description = "The uncompromising code formatter." -optional = false -python-versions = ">=3.8" -files = [ - {file = "black-24.8.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:09cdeb74d494ec023ded657f7092ba518e8cf78fa8386155e4a03fdcc44679e6"}, - {file = "black-24.8.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81c6742da39f33b08e791da38410f32e27d632260e599df7245cccee2064afeb"}, - {file = "black-24.8.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:707a1ca89221bc8a1a64fb5e15ef39cd755633daa672a9db7498d1c19de66a42"}, - {file = "black-24.8.0-cp310-cp310-win_amd64.whl", hash = "sha256:d6417535d99c37cee4091a2f24eb2b6d5ec42b144d50f1f2e436d9fe1916fe1a"}, - {file = "black-24.8.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fb6e2c0b86bbd43dee042e48059c9ad7830abd5c94b0bc518c0eeec57c3eddc1"}, - {file = "black-24.8.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:837fd281f1908d0076844bc2b801ad2d369c78c45cf800cad7b61686051041af"}, - {file = "black-24.8.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:62e8730977f0b77998029da7971fa896ceefa2c4c4933fcd593fa599ecbf97a4"}, - {file = "black-24.8.0-cp311-cp311-win_amd64.whl", hash = "sha256:72901b4913cbac8972ad911dc4098d5753704d1f3c56e44ae8dce99eecb0e3af"}, - {file = "black-24.8.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:7c046c1d1eeb7aea9335da62472481d3bbf3fd986e093cffd35f4385c94ae368"}, - {file = "black-24.8.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:649f6d84ccbae73ab767e206772cc2d7a393a001070a4c814a546afd0d423aed"}, - {file = "black-24.8.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2b59b250fdba5f9a9cd9d0ece6e6d993d91ce877d121d161e4698af3eb9c1018"}, - {file = "black-24.8.0-cp312-cp312-win_amd64.whl", hash = "sha256:6e55d30d44bed36593c3163b9bc63bf58b3b30e4611e4d88a0c3c239930ed5b2"}, - {file = "black-24.8.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:505289f17ceda596658ae81b61ebbe2d9b25aa78067035184ed0a9d855d18afd"}, - {file = "black-24.8.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:b19c9ad992c7883ad84c9b22aaa73562a16b819c1d8db7a1a1a49fb7ec13c7d2"}, - {file = "black-24.8.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1f13f7f386f86f8121d76599114bb8c17b69d962137fc70efe56137727c7047e"}, - {file = "black-24.8.0-cp38-cp38-win_amd64.whl", hash = "sha256:f490dbd59680d809ca31efdae20e634f3fae27fba3ce0ba3208333b713bc3920"}, - {file = "black-24.8.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:eab4dd44ce80dea27dc69db40dab62d4ca96112f87996bca68cd75639aeb2e4c"}, - {file = "black-24.8.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:3c4285573d4897a7610054af5a890bde7c65cb466040c5f0c8b732812d7f0e5e"}, - {file = "black-24.8.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9e84e33b37be070ba135176c123ae52a51f82306def9f7d063ee302ecab2cf47"}, - {file = "black-24.8.0-cp39-cp39-win_amd64.whl", hash = "sha256:73bbf84ed136e45d451a260c6b73ed674652f90a2b3211d6a35e78054563a9bb"}, - {file = "black-24.8.0-py3-none-any.whl", hash = "sha256:972085c618ee94f402da1af548a4f218c754ea7e5dc70acb168bfaca4c2542ed"}, - {file = "black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f"}, +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "black-25.1.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:759e7ec1e050a15f89b770cefbf91ebee8917aac5c20483bc2d80a6c3a04df32"}, + {file = "black-25.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e519ecf93120f34243e6b0054db49c00a35f84f195d5bce7e9f5cfc578fc2da"}, + {file = "black-25.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:055e59b198df7ac0b7efca5ad7ff2516bca343276c466be72eb04a3bcc1f82d7"}, + {file = "black-25.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:db8ea9917d6f8fc62abd90d944920d95e73c83a5ee3383493e35d271aca872e9"}, + {file = "black-25.1.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a39337598244de4bae26475f77dda852ea00a93bd4c728e09eacd827ec929df0"}, + {file = "black-25.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:96c1c7cd856bba8e20094e36e0f948718dc688dba4a9d78c3adde52b9e6c2299"}, + {file = "black-25.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bce2e264d59c91e52d8000d507eb20a9aca4a778731a08cfff7e5ac4a4bb7096"}, + {file = "black-25.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:172b1dbff09f86ce6f4eb8edf9dede08b1fce58ba194c87d7a4f1a5aa2f5b3c2"}, + {file = "black-25.1.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4b60580e829091e6f9238c848ea6750efed72140b91b048770b64e74fe04908b"}, + {file = "black-25.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1e2978f6df243b155ef5fa7e558a43037c3079093ed5d10fd84c43900f2d8ecc"}, + {file = "black-25.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3b48735872ec535027d979e8dcb20bf4f70b5ac75a8ea99f127c106a7d7aba9f"}, + {file = "black-25.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:ea0213189960bda9cf99be5b8c8ce66bb054af5e9e861249cd23471bd7b0b3ba"}, + {file = "black-25.1.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:8f0b18a02996a836cc9c9c78e5babec10930862827b1b724ddfe98ccf2f2fe4f"}, + {file = "black-25.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:afebb7098bfbc70037a053b91ae8437c3857482d3a690fefc03e9ff7aa9a5fd3"}, + {file = "black-25.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:030b9759066a4ee5e5aca28c3c77f9c64789cdd4de8ac1df642c40b708be6171"}, + {file = "black-25.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:a22f402b410566e2d1c950708c77ebf5ebd5d0d88a6a2e87c86d9fb48afa0d18"}, + {file = "black-25.1.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:a1ee0a0c330f7b5130ce0caed9936a904793576ef4d2b98c40835d6a65afa6a0"}, + {file = "black-25.1.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f3df5f1bf91d36002b0a75389ca8663510cf0531cca8aa5c1ef695b46d98655f"}, + {file = "black-25.1.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d9e6827d563a2c820772b32ce8a42828dc6790f095f441beef18f96aa6f8294e"}, + {file = "black-25.1.0-cp39-cp39-win_amd64.whl", hash = "sha256:bacabb307dca5ebaf9c118d2d2f6903da0d62c9faa82bd21a33eecc319559355"}, + {file = "black-25.1.0-py3-none-any.whl", hash = "sha256:95e8176dae143ba9097f351d174fdaf0ccd29efb414b362ae3fd72bf0f710717"}, + {file = "black-25.1.0.tar.gz", hash = "sha256:33496d5cd1222ad73391352b4ae8da15253c5de89b93a80b3e2c8d9a19ec2666"}, ] [package.dependencies] @@ -110,38 +60,40 @@ typing-extensions = {version = ">=4.0.1", markers = "python_version < \"3.11\""} [package.extras] colorama = ["colorama (>=0.4.3)"] -d = ["aiohttp (>=3.7.4)", "aiohttp (>=3.7.4,!=3.9.0)"] +d = ["aiohttp (>=3.10)"] jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.33.13" +version = "1.39.16" description = "The AWS SDK for Python" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "boto3-1.33.13-py3-none-any.whl", hash = "sha256:5f278b95fb2b32f3d09d950759a05664357ba35d81107bab1537c4ddd212cd8c"}, - {file = "boto3-1.33.13.tar.gz", hash = "sha256:0e966b8a475ecb06cc0846304454b8da2473d4c8198a45dfb2c5304871986883"}, + {file = "boto3-1.39.16-py3-none-any.whl", hash = "sha256:cf843228928fd1caebb46c21fbd757a390ce22672b937a354ae89a1d16cb99f8"}, + {file = "boto3-1.39.16.tar.gz", hash = "sha256:d4ce6ba5c030d7ff2033b35e5574d2414e42b80b937bf40d080e11c4d9d0acc1"}, ] [package.dependencies] -botocore = ">=1.33.13,<1.34.0" +botocore = ">=1.39.16,<1.40.0" jmespath = ">=0.7.1,<2.0.0" -s3transfer = ">=0.8.2,<0.9.0" +s3transfer = ">=0.13.0,<0.14.0" [package.extras] crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.33.13" +version = "1.39.16" description = "Low-level, data-driven core of boto 3." optional = false -python-versions = ">= 3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "botocore-1.33.13-py3-none-any.whl", hash = "sha256:aeadccf4b7c674c7d47e713ef34671b834bc3e89723ef96d994409c9f54666e6"}, - {file = "botocore-1.33.13.tar.gz", hash = "sha256:fb577f4cb175605527458b04571451db1bd1a2036976b626206036acd4496617"}, + {file = "botocore-1.39.16-py3-none-any.whl", hash = "sha256:1f1c3b614ac88fd68f824c481cfd7686460c38fe13c01e2963556e7186be3248"}, + {file = "botocore-1.39.16.tar.gz", hash = "sha256:b5a1416849637aa8e72292ee3e7b11cd0c22f9b96f6043d2ac6ba0092a193188"}, ] [package.dependencies] @@ -149,56 +101,60 @@ jmespath = ">=0.7.1,<2.0.0" python-dateutil = ">=2.1,<3.0.0" urllib3 = [ {version = ">=1.25.4,<1.27", markers = "python_version < \"3.10\""}, - {version = ">=1.25.4,<2.1", markers = "python_version >= \"3.10\""}, + {version = ">=1.25.4,<2.2.0 || >2.2.0,<3", markers = "python_version >= \"3.10\""}, ] [package.extras] -crt = ["awscrt (==0.19.17)"] +crt = ["awscrt (==0.23.8)"] [[package]] name = "build" -version = "1.1.1" +version = "1.2.2.post1" description = "A simple, correct Python build frontend" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "build-1.1.1-py3-none-any.whl", hash = "sha256:8ed0851ee76e6e38adce47e4bee3b51c771d86c64cf578d0c2245567ee200e73"}, - {file = "build-1.1.1.tar.gz", hash = "sha256:8eea65bb45b1aac2e734ba2cc8dad3a6d97d97901a395bd0ed3e7b46953d2a31"}, + {file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"}, + {file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"}, ] [package.dependencies] colorama = {version = "*", markers = "os_name == \"nt\""} importlib-metadata = {version = ">=4.6", markers = "python_full_version < \"3.10.2\""} -packaging = ">=19.0" +packaging = ">=19.1" pyproject_hooks = "*" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] -test = ["filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0)", "setuptools (>=56.0.0)", "setuptools (>=56.0.0)", "setuptools (>=67.8.0)", "wheel (>=0.36.0)"] -typing = ["importlib-metadata (>=5.1)", "mypy (>=1.5.0,<1.6.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0) ; python_version < \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.11\"", "setuptools (>=67.8.0) ; python_version >= \"3.12\"", "wheel (>=0.36.0)"] +typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] +uv = ["uv (>=0.1.18)"] virtualenv = ["virtualenv (>=20.0.35)"] [[package]] name = "cachetools" -version = "5.5.0" +version = "6.1.0" description = "Extensible memoizing collections and decorators" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "cachetools-5.5.0-py3-none-any.whl", hash = "sha256:02134e8439cdc2ffb62023ce1debca2944c3f289d66bb17ead3ab3dede74b292"}, - {file = "cachetools-5.5.0.tar.gz", hash = "sha256:2cc24fb4cbe39633fb7badd9db9ca6295d766d9c2995f245725a46715d050f2a"}, + {file = "cachetools-6.1.0-py3-none-any.whl", hash = "sha256:1c7bb3cf9193deaf3508b7c5f2a79986c13ea38965c5adcff1f84519cf39163e"}, + {file = "cachetools-6.1.0.tar.gz", hash = "sha256:b4c4f404392848db3ce7aac34950d17be4d864da4b8b66911008e430bc544587"}, ] [[package]] name = "certifi" -version = "2024.7.4" +version = "2025.7.14" description = "Python package for providing Mozilla's CA Bundle." optional = false -python-versions = ">=3.6" +python-versions = ">=3.7" +groups = ["main"] files = [ - {file = "certifi-2024.7.4-py3-none-any.whl", hash = "sha256:c198e21b1289c2ab85ee4e67bb4b4ef3ead0892059901a8d5b622f24a1101e90"}, - {file = "certifi-2024.7.4.tar.gz", hash = "sha256:5a1e7645bc0ec61a09e26c36f6106dd4cf40c6db3a1fb6352b0244e7fb057c7b"}, + {file = "certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2"}, + {file = "certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995"}, ] [[package]] @@ -207,6 +163,7 @@ version = "5.2.0" description = "Universal encoding detector for Python 3" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "chardet-5.2.0-py3-none-any.whl", hash = "sha256:e1cf59446890a00105fe7b7912492ea04b6e6f06d4b742b2c788469e34c82970"}, {file = "chardet-5.2.0.tar.gz", hash = "sha256:1b3b6ff479a8c414bc3fa2c0852995695c4a026dcd6d0633b2dd092ca39c1cf7"}, @@ -214,117 +171,137 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.3.2" +version = "3.4.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false -python-versions = ">=3.7.0" -files = [ - {file = "charset-normalizer-3.3.2.tar.gz", hash = "sha256:f30c3cb33b24454a82faecaf01b19c18562b1e89558fb6c56de4d9118a032fd5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:25baf083bf6f6b341f4121c2f3c548875ee6f5339300e08be3f2b2ba1721cdd3"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:06435b539f889b1f6f4ac1758871aae42dc3a8c0e24ac9e60c2384973ad73027"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9063e24fdb1e498ab71cb7419e24622516c4a04476b17a2dab57e8baa30d6e03"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6897af51655e3691ff853668779c7bad41579facacf5fd7253b0133308cf000d"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1d3193f4a680c64b4b6a9115943538edb896edc190f0b222e73761716519268e"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd70574b12bb8a4d2aaa0094515df2463cb429d8536cfb6c7ce983246983e5a6"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8465322196c8b4d7ab6d1e049e4c5cb460d0394da4a27d23cc242fbf0034b6b5"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a9a8e9031d613fd2009c182b69c7b2c1ef8239a0efb1df3f7c8da66d5dd3d537"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:beb58fe5cdb101e3a055192ac291b7a21e3b7ef4f67fa1d74e331a7f2124341c"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:e06ed3eb3218bc64786f7db41917d4e686cc4856944f53d5bdf83a6884432e12"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:2e81c7b9c8979ce92ed306c249d46894776a909505d8f5a4ba55b14206e3222f"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:572c3763a264ba47b3cf708a44ce965d98555f618ca42c926a9c1616d8f34269"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fd1abc0d89e30cc4e02e4064dc67fcc51bd941eb395c502aac3ec19fab46b519"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win32.whl", hash = "sha256:3d47fa203a7bd9c5b6cee4736ee84ca03b8ef23193c0d1ca99b5089f72645c73"}, - {file = "charset_normalizer-3.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:10955842570876604d404661fbccbc9c7e684caf432c09c715ec38fbae45ae09"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:802fe99cca7457642125a8a88a084cef28ff0cf9407060f7b93dca5aa25480db"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:573f6eac48f4769d667c4442081b1794f52919e7edada77495aaed9236d13a96"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549a3a73da901d5bc3ce8d24e0600d1fa85524c10287f6004fbab87672bf3e1e"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f27273b60488abe721a075bcca6d7f3964f9f6f067c8c4c605743023d7d3944f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ceae2f17a9c33cb48e3263960dc5fc8005351ee19db217e9b1bb15d28c02574"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65f6f63034100ead094b8744b3b97965785388f308a64cf8d7c34f2f2e5be0c4"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:753f10e867343b4511128c6ed8c82f7bec3bd026875576dfd88483c5c73b2fd8"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4a78b2b446bd7c934f5dcedc588903fb2f5eec172f3d29e52a9096a43722adfc"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e537484df0d8f426ce2afb2d0f8e1c3d0b114b83f8850e5f2fbea0e797bd82ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:eb6904c354526e758fda7167b33005998fb68c46fbc10e013ca97f21ca5c8887"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:deb6be0ac38ece9ba87dea880e438f25ca3eddfac8b002a2ec3d9183a454e8ae"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:4ab2fe47fae9e0f9dee8c04187ce5d09f48eabe611be8259444906793ab7cbce"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:80402cd6ee291dcb72644d6eac93785fe2c8b9cb30893c1af5b8fdd753b9d40f"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win32.whl", hash = "sha256:7cd13a2e3ddeed6913a65e66e94b51d80a041145a026c27e6bb76c31a853c6ab"}, - {file = "charset_normalizer-3.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:663946639d296df6a2bb2aa51b60a2454ca1cb29835324c640dafb5ff2131a77"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:0b2b64d2bb6d3fb9112bafa732def486049e63de9618b5843bcdd081d8144cd8"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:ddbb2551d7e0102e7252db79ba445cdab71b26640817ab1e3e3648dad515003b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:55086ee1064215781fff39a1af09518bc9255b50d6333f2e4c74ca09fac6a8f6"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f4a014bc36d3c57402e2977dada34f9c12300af536839dc38c0beab8878f38a"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a10af20b82360ab00827f916a6058451b723b4e65030c5a18577c8b2de5b3389"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d756e44e94489e49571086ef83b2bb8ce311e730092d2c34ca8f7d925cb20aa"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:90d558489962fd4918143277a773316e56c72da56ec7aa3dc3dbbe20fdfed15b"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6ac7ffc7ad6d040517be39eb591cac5ff87416c2537df6ba3cba3bae290c0fed"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7ed9e526742851e8d5cc9e6cf41427dfc6068d4f5a3bb03659444b4cabf6bc26"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:8bdb58ff7ba23002a4c5808d608e4e6c687175724f54a5dade5fa8c67b604e4d"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:6b3251890fff30ee142c44144871185dbe13b11bab478a88887a639655be1068"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:b4a23f61ce87adf89be746c8a8974fe1c823c891d8f86eb218bb957c924bb143"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:efcb3f6676480691518c177e3b465bcddf57cea040302f9f4e6e191af91174d4"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win32.whl", hash = "sha256:d965bba47ddeec8cd560687584e88cf699fd28f192ceb452d1d7ee807c5597b7"}, - {file = "charset_normalizer-3.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:96b02a3dc4381e5494fad39be677abcb5e6634bf7b4fa83a6dd3112607547001"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:95f2a5796329323b8f0512e09dbb7a1860c46a39da62ecb2324f116fa8fdc85c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c002b4ffc0be611f0d9da932eb0f704fe2602a9a949d1f738e4c34c75b0863d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a981a536974bbc7a512cf44ed14938cf01030a99e9b3a06dd59578882f06f985"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3287761bc4ee9e33561a7e058c72ac0938c4f57fe49a09eae428fd88aafe7bb6"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42cb296636fcc8b0644486d15c12376cb9fa75443e00fb25de0b8602e64c1714"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a55554a2fa0d408816b3b5cedf0045f4b8e1a6065aec45849de2d6f3f8e9786"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:c083af607d2515612056a31f0a8d9e0fcb5876b7bfc0abad3ecd275bc4ebc2d5"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:87d1351268731db79e0f8e745d92493ee2841c974128ef629dc518b937d9194c"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:bd8f7df7d12c2db9fab40bdd87a7c09b1530128315d047a086fa3ae3435cb3a8"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:c180f51afb394e165eafe4ac2936a14bee3eb10debc9d9e4db8958fe36afe711"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:8c622a5fe39a48f78944a87d4fb8a53ee07344641b0562c540d840748571b811"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win32.whl", hash = "sha256:db364eca23f876da6f9e16c9da0df51aa4f104a972735574842618b8c6d999d4"}, - {file = "charset_normalizer-3.3.2-cp37-cp37m-win_amd64.whl", hash = "sha256:86216b5cee4b06df986d214f664305142d9c76df9b6512be2738aa72a2048f99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:6463effa3186ea09411d50efc7d85360b38d5f09b870c48e4600f63af490e56a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:6c4caeef8fa63d06bd437cd4bdcf3ffefe6738fb1b25951440d80dc7df8c03ac"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:37e55c8e51c236f95b033f6fb391d7d7970ba5fe7ff453dad675e88cf303377a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fb69256e180cb6c8a894fee62b3afebae785babc1ee98b81cdf68bbca1987f33"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ae5f4161f18c61806f411a13b0310bea87f987c7d2ecdbdaad0e94eb2e404238"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b2b0a0c0517616b6869869f8c581d4eb2dd83a4d79e0ebcb7d373ef9956aeb0a"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:45485e01ff4d3630ec0d9617310448a8702f70e9c01906b0d0118bdf9d124cf2"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb00ed941194665c332bf8e078baf037d6c35d7c4f3102ea2d4f16ca94a26dc8"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:2127566c664442652f024c837091890cb1942c30937add288223dc895793f898"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:a50aebfa173e157099939b17f18600f72f84eed3049e743b68ad15bd69b6bf99"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:4d0d1650369165a14e14e1e47b372cfcb31d6ab44e6e33cb2d4e57265290044d"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:923c0c831b7cfcb071580d3f46c4baf50f174be571576556269530f4bbd79d04"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:06a81e93cd441c56a9b65d8e1d043daeb97a3d0856d177d5c90ba85acb3db087"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win32.whl", hash = "sha256:6ef1d82a3af9d3eecdba2321dc1b3c238245d890843e040e41e470ffa64c3e25"}, - {file = "charset_normalizer-3.3.2-cp38-cp38-win_amd64.whl", hash = "sha256:eb8821e09e916165e160797a6c17edda0679379a4be5c716c260e836e122f54b"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:c235ebd9baae02f1b77bcea61bce332cb4331dc3617d254df3323aa01ab47bd4"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5b4c145409bef602a690e7cfad0a15a55c13320ff7a3ad7ca59c13bb8ba4d45d"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:68d1f8a9e9e37c1223b656399be5d6b448dea850bed7d0f87a8311f1ff3dabb0"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:22afcb9f253dac0696b5a4be4a1c0f8762f8239e21b99680099abd9b2b1b2269"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e27ad930a842b4c5eb8ac0016b0a54f5aebbe679340c26101df33424142c143c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1f79682fbe303db92bc2b1136016a38a42e835d932bab5b3b1bfcfbf0640e519"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b261ccdec7821281dade748d088bb6e9b69e6d15b30652b74cbbac25e280b796"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:122c7fa62b130ed55f8f285bfd56d5f4b4a5b503609d181f9ad85e55c89f4185"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:d0eccceffcb53201b5bfebb52600a5fb483a20b61da9dbc885f8b103cbe7598c"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:9f96df6923e21816da7e0ad3fd47dd8f94b2a5ce594e00677c0013018b813458"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:7f04c839ed0b6b98b1a7501a002144b76c18fb1c1850c8b98d458ac269e26ed2"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:34d1c8da1e78d2e001f363791c98a272bb734000fcef47a491c1e3b0505657a8"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ff8fa367d09b717b2a17a052544193ad76cd49979c805768879cb63d9ca50561"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win32.whl", hash = "sha256:aed38f6e4fb3f5d6bf81bfa990a07806be9d83cf7bacef998ab1a9bd660a581f"}, - {file = "charset_normalizer-3.3.2-cp39-cp39-win_amd64.whl", hash = "sha256:b01b88d45a6fcb69667cd6d2f7a9aeb4bf53760d7fc536bf679ec94fe9f3ff3d"}, - {file = "charset_normalizer-3.3.2-py3-none-any.whl", hash = "sha256:3e4d1f6587322d2788836a99c69062fbb091331ec940e02d12d179c1d53e25fc"}, +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a"}, + {file = "charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a"}, + {file = "charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c"}, + {file = "charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7"}, + {file = "charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1cad5f45b3146325bb38d6855642f6fd609c3f7cad4dbaf75549bf3b904d3184"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b2680962a4848b3c4f155dc2ee64505a9c57186d0d56b43123b17ca3de18f0fa"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:36b31da18b8890a76ec181c3cf44326bf2c48e36d393ca1b72b3f484113ea344"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f4074c5a429281bf056ddd4c5d3b740ebca4d43ffffe2ef4bf4d2d05114299da"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c9e36a97bee9b86ef9a1cf7bb96747eb7a15c2f22bdb5b516434b00f2a599f02"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:1b1bde144d98e446b056ef98e59c256e9294f6b74d7af6846bf5ffdafd687a7d"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:915f3849a011c1f593ab99092f3cecfcb4d65d8feb4a64cf1bf2d22074dc0ec4"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:fb707f3e15060adf5b7ada797624a6c6e0138e2a26baa089df64c68ee98e040f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:25a23ea5c7edc53e0f29bae2c44fcb5a1aa10591aae107f2a2b2583a9c5cbc64"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:770cab594ecf99ae64c236bc9ee3439c3f46be49796e265ce0cc8bc17b10294f"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win32.whl", hash = "sha256:6a0289e4589e8bdfef02a80478f1dfcb14f0ab696b5a00e1f4b8a14a307a3c58"}, + {file = "charset_normalizer-3.4.2-cp37-cp37m-win_amd64.whl", hash = "sha256:6fc1f5b51fa4cecaa18f2bd7a003f3dd039dd615cd69a2afd6d3b19aed6775f2"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:76af085e67e56c8816c3ccf256ebd136def2ed9654525348cfa744b6802b69eb"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e45ba65510e2647721e35323d6ef54c7974959f6081b58d4ef5d87c60c84919a"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:046595208aae0120559a67693ecc65dd75d46f7bf687f159127046628178dc45"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:75d10d37a47afee94919c4fab4c22b9bc2a8bf7d4f46f87363bcf0573f3ff4f5"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6333b3aa5a12c26b2a4d4e7335a28f1475e0e5e17d69d55141ee3cab736f66d1"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e8323a9b031aa0393768b87f04b4164a40037fb2a3c11ac06a03ffecd3618027"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:24498ba8ed6c2e0b56d4acbf83f2d989720a93b41d712ebd4f4979660db4417b"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:844da2b5728b5ce0e32d863af26f32b5ce61bc4273a9c720a9f3aa9df73b1455"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:65c981bdbd3f57670af8b59777cbfae75364b483fa8a9f420f08094531d54a01"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:3c21d4fca343c805a52c0c78edc01e3477f6dd1ad7c47653241cf2a206d4fc58"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dc7039885fa1baf9be153a0626e337aa7ec8bf96b0128605fb0d77788ddc1681"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win32.whl", hash = "sha256:8272b73e1c5603666618805fe821edba66892e2870058c94c53147602eab29c7"}, + {file = "charset_normalizer-3.4.2-cp38-cp38-win_amd64.whl", hash = "sha256:70f7172939fdf8790425ba31915bfbe8335030f05b9913d7ae00a87d4395620a"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:005fa3432484527f9732ebd315da8da8001593e2cf46a3d817669f062c3d9ed4"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e92fca20c46e9f5e1bb485887d074918b13543b1c2a1185e69bb8d17ab6236a7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:50bf98d5e563b83cc29471fa114366e6806bc06bc7a25fd59641e41445327836"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:721c76e84fe669be19c5791da68232ca2e05ba5185575086e384352e2c309597"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:82d8fd25b7f4675d0c47cf95b594d4e7b158aca33b76aa63d07186e13c0e0ab7"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b3daeac64d5b371dea99714f08ffc2c208522ec6b06fbc7866a450dd446f5c0f"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:dccab8d5fa1ef9bfba0590ecf4d46df048d18ffe3eec01eeb73a42e0d9e7a8ba"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aaf27faa992bfee0264dc1f03f4c75e9fcdda66a519db6b957a3f826e285cf12"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:eb30abc20df9ab0814b5a2524f23d75dcf83cde762c161917a2b4b7b55b1e518"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:c72fbbe68c6f32f251bdc08b8611c7b3060612236e960ef848e0a517ddbe76c5"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:982bb1e8b4ffda883b3d0a521e23abcd6fd17418f6d2c4118d257a10199c0ce3"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win32.whl", hash = "sha256:43e0933a0eff183ee85833f341ec567c0980dae57c464d8a508e1b2ceb336471"}, + {file = "charset_normalizer-3.4.2-cp39-cp39-win_amd64.whl", hash = "sha256:d11b54acf878eef558599658b0ffca78138c8c3655cf4f3a4a673c437e67732e"}, + {file = "charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0"}, + {file = "charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63"}, ] [[package]] name = "click" -version = "8.1.7" +version = "8.1.8" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version == \"3.9\"" files = [ - {file = "click-8.1.7-py3-none-any.whl", hash = "sha256:ae74fb96c20a0277a1d615f1e4d73c8414f5a98db8b799a7931d1582f3390c28"}, - {file = "click-8.1.7.tar.gz", hash = "sha256:ca9853ad459e787e2192211578cc907e7594e294c7ccc834310722b41b9ca6de"}, + {file = "click-8.1.8-py3-none-any.whl", hash = "sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2"}, + {file = "click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "click" +version = "8.2.1" +description = "Composable command line interface toolkit" +optional = false +python-versions = ">=3.10" +groups = ["dev"] +markers = "python_version >= \"3.10\"" +files = [ + {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"}, + {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"}, ] [package.dependencies] colorama = {version = "*", markers = "platform_system == \"Windows\""} -importlib-metadata = {version = "*", markers = "python_version < \"3.8\""} [[package]] name = "colorama" @@ -332,188 +309,241 @@ 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 = ["dev", "local"] 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 = {local = "python_version < \"4.0\" and sys_platform == \"win32\""} [[package]] name = "coverage" -version = "7.2.7" +version = "7.10.1" description = "Code coverage measurement for Python" optional = false -python-versions = ">=3.7" -files = [ - {file = "coverage-7.2.7-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d39b5b4f2a66ccae8b7263ac3c8170994b65266797fb96cbbfd3fb5b23921db8"}, - {file = "coverage-7.2.7-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6d040ef7c9859bb11dfeb056ff5b3872436e3b5e401817d87a31e1750b9ae2fb"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba90a9563ba44a72fda2e85302c3abc71c5589cea608ca16c22b9804262aaeb6"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7d9405291c6928619403db1d10bd07888888ec1abcbd9748fdaa971d7d661b2"}, - {file = "coverage-7.2.7-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:31563e97dae5598556600466ad9beea39fb04e0229e61c12eaa206e0aa202063"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:ebba1cd308ef115925421d3e6a586e655ca5a77b5bf41e02eb0e4562a111f2d1"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:cb017fd1b2603ef59e374ba2063f593abe0fc45f2ad9abdde5b4d83bd922a353"}, - {file = "coverage-7.2.7-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d62a5c7dad11015c66fbb9d881bc4caa5b12f16292f857842d9d1871595f4495"}, - {file = "coverage-7.2.7-cp310-cp310-win32.whl", hash = "sha256:ee57190f24fba796e36bb6d3aa8a8783c643d8fa9760c89f7a98ab5455fbf818"}, - {file = "coverage-7.2.7-cp310-cp310-win_amd64.whl", hash = "sha256:f75f7168ab25dd93110c8a8117a22450c19976afbc44234cbf71481094c1b850"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06a9a2be0b5b576c3f18f1a241f0473575c4a26021b52b2a85263a00f034d51f"}, - {file = "coverage-7.2.7-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5baa06420f837184130752b7c5ea0808762083bf3487b5038d68b012e5937dbe"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fdec9e8cbf13a5bf63290fc6013d216a4c7232efb51548594ca3631a7f13c3a3"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:52edc1a60c0d34afa421c9c37078817b2e67a392cab17d97283b64c5833f427f"}, - {file = "coverage-7.2.7-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63426706118b7f5cf6bb6c895dc215d8a418d5952544042c8a2d9fe87fcf09cb"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:afb17f84d56068a7c29f5fa37bfd38d5aba69e3304af08ee94da8ed5b0865833"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:48c19d2159d433ccc99e729ceae7d5293fbffa0bdb94952d3579983d1c8c9d97"}, - {file = "coverage-7.2.7-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:0e1f928eaf5469c11e886fe0885ad2bf1ec606434e79842a879277895a50942a"}, - {file = "coverage-7.2.7-cp311-cp311-win32.whl", hash = "sha256:33d6d3ea29d5b3a1a632b3c4e4f4ecae24ef170b0b9ee493883f2df10039959a"}, - {file = "coverage-7.2.7-cp311-cp311-win_amd64.whl", hash = "sha256:5b7540161790b2f28143191f5f8ec02fb132660ff175b7747b95dcb77ac26562"}, - {file = "coverage-7.2.7-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f2f67fe12b22cd130d34d0ef79206061bfb5eda52feb6ce0dba0644e20a03cf4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a342242fe22407f3c17f4b499276a02b01e80f861f1682ad1d95b04018e0c0d4"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:171717c7cb6b453aebac9a2ef603699da237f341b38eebfee9be75d27dc38e01"}, - {file = "coverage-7.2.7-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49969a9f7ffa086d973d91cec8d2e31080436ef0fb4a359cae927e742abfaaa6"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:b46517c02ccd08092f4fa99f24c3b83d8f92f739b4657b0f146246a0ca6a831d"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:a3d33a6b3eae87ceaefa91ffdc130b5e8536182cd6dfdbfc1aa56b46ff8c86de"}, - {file = "coverage-7.2.7-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:976b9c42fb2a43ebf304fa7d4a310e5f16cc99992f33eced91ef6f908bd8f33d"}, - {file = "coverage-7.2.7-cp312-cp312-win32.whl", hash = "sha256:8de8bb0e5ad103888d65abef8bca41ab93721647590a3f740100cd65c3b00511"}, - {file = "coverage-7.2.7-cp312-cp312-win_amd64.whl", hash = "sha256:9e31cb64d7de6b6f09702bb27c02d1904b3aebfca610c12772452c4e6c21a0d3"}, - {file = "coverage-7.2.7-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:58c2ccc2f00ecb51253cbe5d8d7122a34590fac9646a960d1430d5b15321d95f"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d22656368f0e6189e24722214ed8d66b8022db19d182927b9a248a2a8a2f67eb"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a895fcc7b15c3fc72beb43cdcbdf0ddb7d2ebc959edac9cef390b0d14f39f8a9"}, - {file = "coverage-7.2.7-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e84606b74eb7de6ff581a7915e2dab7a28a0517fbe1c9239eb227e1354064dcd"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:0a5f9e1dbd7fbe30196578ca36f3fba75376fb99888c395c5880b355e2875f8a"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:419bfd2caae268623dd469eff96d510a920c90928b60f2073d79f8fe2bbc5959"}, - {file = "coverage-7.2.7-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:2aee274c46590717f38ae5e4650988d1af340fe06167546cc32fe2f58ed05b02"}, - {file = "coverage-7.2.7-cp37-cp37m-win32.whl", hash = "sha256:61b9a528fb348373c433e8966535074b802c7a5d7f23c4f421e6c6e2f1697a6f"}, - {file = "coverage-7.2.7-cp37-cp37m-win_amd64.whl", hash = "sha256:b1c546aca0ca4d028901d825015dc8e4d56aac4b541877690eb76490f1dc8ed0"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:54b896376ab563bd38453cecb813c295cf347cf5906e8b41d340b0321a5433e5"}, - {file = "coverage-7.2.7-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:3d376df58cc111dc8e21e3b6e24606b5bb5dee6024f46a5abca99124b2229ef5"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e330fc79bd7207e46c7d7fd2bb4af2963f5f635703925543a70b99574b0fea9"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e9d683426464e4a252bf70c3498756055016f99ddaec3774bf368e76bbe02b6"}, - {file = "coverage-7.2.7-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8d13c64ee2d33eccf7437961b6ea7ad8673e2be040b4f7fd4fd4d4d28d9ccb1e"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b7aa5f8a41217360e600da646004f878250a0d6738bcdc11a0a39928d7dc2050"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:8fa03bce9bfbeeef9f3b160a8bed39a221d82308b4152b27d82d8daa7041fee5"}, - {file = "coverage-7.2.7-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:245167dd26180ab4c91d5e1496a30be4cd721a5cf2abf52974f965f10f11419f"}, - {file = "coverage-7.2.7-cp38-cp38-win32.whl", hash = "sha256:d2c2db7fd82e9b72937969bceac4d6ca89660db0a0967614ce2481e81a0b771e"}, - {file = "coverage-7.2.7-cp38-cp38-win_amd64.whl", hash = "sha256:2e07b54284e381531c87f785f613b833569c14ecacdcb85d56b25c4622c16c3c"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:537891ae8ce59ef63d0123f7ac9e2ae0fc8b72c7ccbe5296fec45fd68967b6c9"}, - {file = "coverage-7.2.7-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:06fb182e69f33f6cd1d39a6c597294cff3143554b64b9825d1dc69d18cc2fff2"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:201e7389591af40950a6480bd9edfa8ed04346ff80002cec1a66cac4549c1ad7"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f6951407391b639504e3b3be51b7ba5f3528adbf1a8ac3302b687ecababf929e"}, - {file = "coverage-7.2.7-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6f48351d66575f535669306aa7d6d6f71bc43372473b54a832222803eb956fd1"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:b29019c76039dc3c0fd815c41392a044ce555d9bcdd38b0fb60fb4cd8e475ba9"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:81c13a1fc7468c40f13420732805a4c38a105d89848b7c10af65a90beff25250"}, - {file = "coverage-7.2.7-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:975d70ab7e3c80a3fe86001d8751f6778905ec723f5b110aed1e450da9d4b7f2"}, - {file = "coverage-7.2.7-cp39-cp39-win32.whl", hash = "sha256:7ee7d9d4822c8acc74a5e26c50604dff824710bc8de424904c0982e25c39c6cb"}, - {file = "coverage-7.2.7-cp39-cp39-win_amd64.whl", hash = "sha256:eb393e5ebc85245347950143969b241d08b52b88a3dc39479822e073a1a8eb27"}, - {file = "coverage-7.2.7-pp37.pp38.pp39-none-any.whl", hash = "sha256:b7b4c971f05e6ae490fef852c218b0e79d4e52f79ef0c8475566584a8fb3e01d"}, - {file = "coverage-7.2.7.tar.gz", hash = "sha256:924d94291ca674905fe9481f12294eb11f2d3d3fd1adb20314ba89e94f44ed59"}, +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "coverage-7.10.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1c86eb388bbd609d15560e7cc0eb936c102b6f43f31cf3e58b4fd9afe28e1372"}, + {file = "coverage-7.10.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6b4ba0f488c1bdb6bd9ba81da50715a372119785458831c73428a8566253b86b"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:083442ecf97d434f0cb3b3e3676584443182653da08b42e965326ba12d6b5f2a"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:c1a40c486041006b135759f59189385da7c66d239bad897c994e18fd1d0c128f"}, + {file = "coverage-7.10.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3beb76e20b28046989300c4ea81bf690df84ee98ade4dc0bbbf774a28eb98440"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:bc265a7945e8d08da28999ad02b544963f813a00f3ed0a7a0ce4165fd77629f8"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:47c91f32ba4ac46f1e224a7ebf3f98b4b24335bad16137737fe71a5961a0665c"}, + {file = "coverage-7.10.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1a108dd78ed185020f66f131c60078f3fae3f61646c28c8bb4edd3fa121fc7fc"}, + {file = "coverage-7.10.1-cp310-cp310-win32.whl", hash = "sha256:7092cc82382e634075cc0255b0b69cb7cada7c1f249070ace6a95cb0f13548ef"}, + {file = "coverage-7.10.1-cp310-cp310-win_amd64.whl", hash = "sha256:ac0c5bba938879c2fc0bc6c1b47311b5ad1212a9dcb8b40fe2c8110239b7faed"}, + {file = "coverage-7.10.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:b45e2f9d5b0b5c1977cb4feb5f594be60eb121106f8900348e29331f553a726f"}, + {file = "coverage-7.10.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3a7a4d74cb0f5e3334f9aa26af7016ddb94fb4bfa11b4a573d8e98ecba8c34f1"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d4b0aab55ad60ead26159ff12b538c85fbab731a5e3411c642b46c3525863437"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:dcc93488c9ebd229be6ee1f0d9aad90da97b33ad7e2912f5495804d78a3cd6b7"}, + {file = "coverage-7.10.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa309df995d020f3438407081b51ff527171cca6772b33cf8f85344b8b4b8770"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cfb8b9d8855c8608f9747602a48ab525b1d320ecf0113994f6df23160af68262"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:320d86da829b012982b414c7cdda65f5d358d63f764e0e4e54b33097646f39a3"}, + {file = "coverage-7.10.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dc60ddd483c556590da1d9482a4518292eec36dd0e1e8496966759a1f282bcd0"}, + {file = "coverage-7.10.1-cp311-cp311-win32.whl", hash = "sha256:4fcfe294f95b44e4754da5b58be750396f2b1caca8f9a0e78588e3ef85f8b8be"}, + {file = "coverage-7.10.1-cp311-cp311-win_amd64.whl", hash = "sha256:efa23166da3fe2915f8ab452dde40319ac84dc357f635737174a08dbd912980c"}, + {file = "coverage-7.10.1-cp311-cp311-win_arm64.whl", hash = "sha256:d12b15a8c3759e2bb580ffa423ae54be4f184cf23beffcbd641f4fe6e1584293"}, + {file = "coverage-7.10.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6b7dc7f0a75a7eaa4584e5843c873c561b12602439d2351ee28c7478186c4da4"}, + {file = "coverage-7.10.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:607f82389f0ecafc565813aa201a5cade04f897603750028dd660fb01797265e"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:f7da31a1ba31f1c1d4d5044b7c5813878adae1f3af8f4052d679cc493c7328f4"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51fe93f3fe4f5d8483d51072fddc65e717a175490804e1942c975a68e04bf97a"}, + {file = "coverage-7.10.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3e59d00830da411a1feef6ac828b90bbf74c9b6a8e87b8ca37964925bba76dbe"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:924563481c27941229cb4e16eefacc35da28563e80791b3ddc5597b062a5c386"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:ca79146ee421b259f8131f153102220b84d1a5e6fb9c8aed13b3badfd1796de6"}, + {file = "coverage-7.10.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2b225a06d227f23f386fdc0eab471506d9e644be699424814acc7d114595495f"}, + {file = "coverage-7.10.1-cp312-cp312-win32.whl", hash = "sha256:5ba9a8770effec5baaaab1567be916c87d8eea0c9ad11253722d86874d885eca"}, + {file = "coverage-7.10.1-cp312-cp312-win_amd64.whl", hash = "sha256:9eb245a8d8dd0ad73b4062135a251ec55086fbc2c42e0eb9725a9b553fba18a3"}, + {file = "coverage-7.10.1-cp312-cp312-win_arm64.whl", hash = "sha256:7718060dd4434cc719803a5e526838a5d66e4efa5dc46d2b25c21965a9c6fcc4"}, + {file = "coverage-7.10.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:ebb08d0867c5a25dffa4823377292a0ffd7aaafb218b5d4e2e106378b1061e39"}, + {file = "coverage-7.10.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f32a95a83c2e17422f67af922a89422cd24c6fa94041f083dd0bb4f6057d0bc7"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:c4c746d11c8aba4b9f58ca8bfc6fbfd0da4efe7960ae5540d1a1b13655ee8892"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7f39edd52c23e5c7ed94e0e4bf088928029edf86ef10b95413e5ea670c5e92d7"}, + {file = "coverage-7.10.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ab6e19b684981d0cd968906e293d5628e89faacb27977c92f3600b201926b994"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5121d8cf0eacb16133501455d216bb5f99899ae2f52d394fe45d59229e6611d0"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:df1c742ca6f46a6f6cbcaef9ac694dc2cb1260d30a6a2f5c68c5f5bcfee1cfd7"}, + {file = "coverage-7.10.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:40f9a38676f9c073bf4b9194707aa1eb97dca0e22cc3766d83879d72500132c7"}, + {file = "coverage-7.10.1-cp313-cp313-win32.whl", hash = "sha256:2348631f049e884839553b9974f0821d39241c6ffb01a418efce434f7eba0fe7"}, + {file = "coverage-7.10.1-cp313-cp313-win_amd64.whl", hash = "sha256:4072b31361b0d6d23f750c524f694e1a417c1220a30d3ef02741eed28520c48e"}, + {file = "coverage-7.10.1-cp313-cp313-win_arm64.whl", hash = "sha256:3e31dfb8271937cab9425f19259b1b1d1f556790e98eb266009e7a61d337b6d4"}, + {file = "coverage-7.10.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:1c4f679c6b573a5257af6012f167a45be4c749c9925fd44d5178fd641ad8bf72"}, + {file = "coverage-7.10.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:871ebe8143da284bd77b84a9136200bd638be253618765d21a1fce71006d94af"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:998c4751dabf7d29b30594af416e4bf5091f11f92a8d88eb1512c7ba136d1ed7"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:780f750a25e7749d0af6b3631759c2c14f45de209f3faaa2398312d1c7a22759"}, + {file = "coverage-7.10.1-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:590bdba9445df4763bdbebc928d8182f094c1f3947a8dc0fc82ef014dbdd8324"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b2df80cb6a2af86d300e70acb82e9b79dab2c1e6971e44b78dbfc1a1e736b53"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:d6a558c2725bfb6337bf57c1cd366c13798bfd3bfc9e3dd1f4a6f6fc95a4605f"}, + {file = "coverage-7.10.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e6150d167f32f2a54690e572e0a4c90296fb000a18e9b26ab81a6489e24e78dd"}, + {file = "coverage-7.10.1-cp313-cp313t-win32.whl", hash = "sha256:d946a0c067aa88be4a593aad1236493313bafaa27e2a2080bfe88db827972f3c"}, + {file = "coverage-7.10.1-cp313-cp313t-win_amd64.whl", hash = "sha256:e37c72eaccdd5ed1130c67a92ad38f5b2af66eeff7b0abe29534225db2ef7b18"}, + {file = "coverage-7.10.1-cp313-cp313t-win_arm64.whl", hash = "sha256:89ec0ffc215c590c732918c95cd02b55c7d0f569d76b90bb1a5e78aa340618e4"}, + {file = "coverage-7.10.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:166d89c57e877e93d8827dac32cedae6b0277ca684c6511497311249f35a280c"}, + {file = "coverage-7.10.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:bed4a2341b33cd1a7d9ffc47df4a78ee61d3416d43b4adc9e18b7d266650b83e"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:ddca1e4f5f4c67980533df01430184c19b5359900e080248bbf4ed6789584d8b"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:37b69226001d8b7de7126cad7366b0778d36777e4d788c66991455ba817c5b41"}, + {file = "coverage-7.10.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b2f22102197bcb1722691296f9e589f02b616f874e54a209284dd7b9294b0b7f"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:1e0c768b0f9ac5839dac5cf88992a4bb459e488ee8a1f8489af4cb33b1af00f1"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:991196702d5e0b120a8fef2664e1b9c333a81d36d5f6bcf6b225c0cf8b0451a2"}, + {file = "coverage-7.10.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ae8e59e5f4fd85d6ad34c2bb9d74037b5b11be072b8b7e9986beb11f957573d4"}, + {file = "coverage-7.10.1-cp314-cp314-win32.whl", hash = "sha256:042125c89cf74a074984002e165d61fe0e31c7bd40ebb4bbebf07939b5924613"}, + {file = "coverage-7.10.1-cp314-cp314-win_amd64.whl", hash = "sha256:a22c3bfe09f7a530e2c94c87ff7af867259c91bef87ed2089cd69b783af7b84e"}, + {file = "coverage-7.10.1-cp314-cp314-win_arm64.whl", hash = "sha256:ee6be07af68d9c4fca4027c70cea0c31a0f1bc9cb464ff3c84a1f916bf82e652"}, + {file = "coverage-7.10.1-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d24fb3c0c8ff0d517c5ca5de7cf3994a4cd559cde0315201511dbfa7ab528894"}, + {file = "coverage-7.10.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1217a54cfd79be20512a67ca81c7da3f2163f51bbfd188aab91054df012154f5"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:51f30da7a52c009667e02f125737229d7d8044ad84b79db454308033a7808ab2"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ed3718c757c82d920f1c94089066225ca2ad7f00bb904cb72b1c39ebdd906ccb"}, + {file = "coverage-7.10.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cc452481e124a819ced0c25412ea2e144269ef2f2534b862d9f6a9dae4bda17b"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:9d6f494c307e5cb9b1e052ec1a471060f1dea092c8116e642e7a23e79d9388ea"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:fc0e46d86905ddd16b85991f1f4919028092b4e511689bbdaff0876bd8aab3dd"}, + {file = "coverage-7.10.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:80b9ccd82e30038b61fc9a692a8dc4801504689651b281ed9109f10cc9fe8b4d"}, + {file = "coverage-7.10.1-cp314-cp314t-win32.whl", hash = "sha256:e58991a2b213417285ec866d3cd32db17a6a88061a985dbb7e8e8f13af429c47"}, + {file = "coverage-7.10.1-cp314-cp314t-win_amd64.whl", hash = "sha256:e88dd71e4ecbc49d9d57d064117462c43f40a21a1383507811cf834a4a620651"}, + {file = "coverage-7.10.1-cp314-cp314t-win_arm64.whl", hash = "sha256:1aadfb06a30c62c2eb82322171fe1f7c288c80ca4156d46af0ca039052814bab"}, + {file = "coverage-7.10.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:57b6e8789cbefdef0667e4a94f8ffa40f9402cee5fc3b8e4274c894737890145"}, + {file = "coverage-7.10.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:85b22a9cce00cb03156334da67eb86e29f22b5e93876d0dd6a98646bb8a74e53"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:97b6983a2f9c76d345ca395e843a049390b39652984e4a3b45b2442fa733992d"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ddf2a63b91399a1c2f88f40bc1705d5a7777e31c7e9eb27c602280f477b582ba"}, + {file = "coverage-7.10.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47ab6dbbc31a14c5486420c2c1077fcae692097f673cf5be9ddbec8cdaa4cdbc"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:21eb7d8b45d3700e7c2936a736f732794c47615a20f739f4133d5230a6512a88"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:283005bb4d98ae33e45f2861cd2cde6a21878661c9ad49697f6951b358a0379b"}, + {file = "coverage-7.10.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fefe31d61d02a8b2c419700b1fade9784a43d726de26495f243b663cd9fe1513"}, + {file = "coverage-7.10.1-cp39-cp39-win32.whl", hash = "sha256:e8ab8e4c7ec7f8a55ac05b5b715a051d74eac62511c6d96d5bb79aaafa3b04cf"}, + {file = "coverage-7.10.1-cp39-cp39-win_amd64.whl", hash = "sha256:c36baa0ecde742784aa76c2b816466d3ea888d5297fda0edbac1bf48fa94688a"}, + {file = "coverage-7.10.1-py3-none-any.whl", hash = "sha256:fa2a258aa6bf188eb9a8948f7102a83da7c430a0dce918dbd8b60ef8fcb772d7"}, + {file = "coverage-7.10.1.tar.gz", hash = "sha256:ae2b4856f29ddfe827106794f3589949a57da6f0d38ab01e24ec35107979ba57"}, ] [package.extras] -toml = ["tomli"] +toml = ["tomli ; python_full_version <= \"3.11.0a6\""] [[package]] name = "decorator" -version = "5.1.1" +version = "5.2.1" description = "Decorators for Humans" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "decorator-5.1.1-py3-none-any.whl", hash = "sha256:b8c3f85900b9dc423225913c5aace94729fe1fa9763b38939a95226f02d37186"}, - {file = "decorator-5.1.1.tar.gz", hash = "sha256:637996211036b6385ef91435e4fae22989472f9d571faba8927ba8253acbc330"}, + {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, + {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, ] [[package]] name = "distlib" -version = "0.3.8" +version = "0.4.0" description = "Distribution utilities" optional = false python-versions = "*" +groups = ["dev"] files = [ - {file = "distlib-0.3.8-py2.py3-none-any.whl", hash = "sha256:034db59a0b96f8ca18035f36290806a9a6e6bd9d1ff91e45a7f172eb17e51784"}, - {file = "distlib-0.3.8.tar.gz", hash = "sha256:1530ea13e350031b6312d8580ddb6b27a104275a31106523b8f123787f494f64"}, + {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 = "exceptiongroup" -version = "1.2.2" +version = "1.3.0" description = "Backport of PEP 654 (exception groups)" optional = false python-versions = ">=3.7" +groups = ["dev", "local"] +markers = "python_version < \"3.11\"" files = [ - {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, - {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, + {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 = "executing" -version = "2.0.1" +version = "2.2.0" description = "Get the currently executing AST node of a frame, and other information" optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "executing-2.0.1-py2.py3-none-any.whl", hash = "sha256:eac49ca94516ccc753f9fb5ce82603156e590b27525a8bc32cce8ae302eb61bc"}, - {file = "executing-2.0.1.tar.gz", hash = "sha256:35afe2ce3affba8ee97f2d69927fa823b08b472b7b994e36a52a964b93d16147"}, + {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, + {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, ] [package.extras] -tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich"] +tests = ["asttokens (>=2.1.0)", "coverage", "coverage-enable-subprocess", "ipython", "littleutils", "pytest", "rich ; python_version >= \"3.11\""] [[package]] name = "filelock" -version = "3.12.2" +version = "3.18.0" description = "A platform independent file lock." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "filelock-3.12.2-py3-none-any.whl", hash = "sha256:cbb791cdea2a72f23da6ac5b5269ab0a0d161e9ef0100e653b69049a7706d1ec"}, - {file = "filelock-3.12.2.tar.gz", hash = "sha256:002740518d8aa59a26b0c76e10fb8c6e15eae825d34b6fdf670333fd7b938d81"}, + {file = "filelock-3.18.0-py3-none-any.whl", hash = "sha256:c401f4f8377c4464e6db25fff06205fd89bdd83b65eb0488ed1b160f780e21de"}, + {file = "filelock-3.18.0.tar.gz", hash = "sha256:adbc88eabb99d2fec8c9c1b229b171f18afa655400173ddc653d5d01501fb9f2"}, ] [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "diff-cover (>=7.5)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "pytest-timeout (>=2.1)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.1.3)", "sphinx-autodoc-typehints (>=3)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.10)", "diff-cover (>=9.2.1)", "pytest (>=8.3.4)", "pytest-asyncio (>=0.25.2)", "pytest-cov (>=6)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.28.1)"] +typing = ["typing-extensions (>=4.12.2) ; python_version < \"3.11\""] [[package]] name = "idna" -version = "3.8" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false python-versions = ">=3.6" +groups = ["main"] files = [ - {file = "idna-3.8-py3-none-any.whl", hash = "sha256:050b4e5baadcd44d760cedbd2b8e639f2ff89bbc7a5730fcc662954303377aac"}, - {file = "idna-3.8.tar.gz", hash = "sha256:d838c2c0ed6fced7693d5e8ab8e734d5f8fda53a039c0164afb0b82e771e3603"}, + {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 = "6.7.0" +version = "8.7.0" description = "Read metadata from Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version < \"3.12\"" files = [ - {file = "importlib_metadata-6.7.0-py3-none-any.whl", hash = "sha256:cb52082e659e97afc5dac71e79de97d8681de3aa07ff18578330904a9d18e5b5"}, - {file = "importlib_metadata-6.7.0.tar.gz", hash = "sha256:1aaf550d4f73e5d6783e7acb77aec43d49da8017410afae93822cc9cca98c4d4"}, + {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, + {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, ] [package.dependencies] -typing-extensions = {version = ">=3.6.4", markers = "python_version < \"3.8\""} -zipp = ">=0.5" +zipp = ">=3.20" [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +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"] -testing = ["flufl.flake8", "importlib-resources (>=1.3)", "packaging", "pyfakefs", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-mypy (>=0.9.1)", "pytest-perf (>=0.9.2)", "pytest-ruff"] +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.0.0" +version = "2.1.0" description = "brain-dead simple config-ini parsing" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"}, - {file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"}, + {file = "iniconfig-2.1.0-py3-none-any.whl", hash = "sha256:9deba5723312380e77435581c6bf4935c94cbfab9b1ed33ef8d238ea168eb760"}, + {file = "iniconfig-2.1.0.tar.gz", hash = "sha256:3abbd2e30b36733fee78f9c7f7308f2d0050e88f0087fd25c2645f63c773e1c7"}, ] [[package]] @@ -522,6 +552,8 @@ version = "8.18.1" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.9" +groups = ["local"] +markers = "python_version == \"3.9\"" files = [ {file = "ipython-8.18.1-py3-none-any.whl", hash = "sha256:e8267419d72d81955ec1177f8a29aaa90ac80ad647499201119e2f05e99aa397"}, {file = "ipython-8.18.1.tar.gz", hash = "sha256:ca6f079bb33457c66e233e4580ebfc4128855b4cf6370dddd73842a9563e8a27"}, @@ -553,24 +585,66 @@ qtconsole = ["qtconsole"] test = ["pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath"] test-extra = ["curio", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.22)", "pandas", "pickleshare", "pytest (<7.1)", "pytest-asyncio (<0.22)", "testpath", "trio"] +[[package]] +name = "ipython" +version = "8.37.0" +description = "IPython: Productive Interactive Computing" +optional = false +python-versions = ">=3.10" +groups = ["local"] +markers = "python_version >= \"3.10\" and python_version < \"4.0\"" +files = [ + {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, + {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, +] + +[package.dependencies] +colorama = {version = "*", markers = "sys_platform == \"win32\""} +decorator = "*" +exceptiongroup = {version = "*", markers = "python_version < \"3.11\""} +jedi = ">=0.16" +matplotlib-inline = "*" +pexpect = {version = ">4.3", markers = "sys_platform != \"win32\" and sys_platform != \"emscripten\""} +prompt_toolkit = ">=3.0.41,<3.1.0" +pygments = ">=2.4.0" +stack_data = "*" +traitlets = ">=5.13.0" +typing_extensions = {version = ">=4.6", markers = "python_version < \"3.12\""} + +[package.extras] +all = ["ipython[black,doc,kernel,matplotlib,nbconvert,nbformat,notebook,parallel,qtconsole]", "ipython[test,test-extra]"] +black = ["black"] +doc = ["docrepr", "exceptiongroup", "intersphinx_registry", "ipykernel", "ipython[test]", "matplotlib", "setuptools (>=18.5)", "sphinx (>=1.3)", "sphinx-rtd-theme", "sphinxcontrib-jquery", "tomli ; python_version < \"3.11\"", "typing_extensions"] +kernel = ["ipykernel"] +matplotlib = ["matplotlib"] +nbconvert = ["nbconvert"] +nbformat = ["nbformat"] +notebook = ["ipywidgets", "notebook"] +parallel = ["ipyparallel"] +qtconsole = ["qtconsole"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test-extra = ["curio", "ipython[test]", "jupyter_ai", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] + [[package]] name = "jedi" -version = "0.19.1" +version = "0.19.2" description = "An autocompletion tool for Python that can be used for text editors." optional = false python-versions = ">=3.6" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "jedi-0.19.1-py2.py3-none-any.whl", hash = "sha256:e983c654fe5c02867aef4cdfce5a2fbb4a50adc0af145f70504238f18ef5e7e0"}, - {file = "jedi-0.19.1.tar.gz", hash = "sha256:cf0496f3651bc65d7174ac1b7d043eff454892c708a87d1b683e57b569927ffd"}, + {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, + {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, ] [package.dependencies] -parso = ">=0.8.3,<0.9.0" +parso = ">=0.8.4,<0.9.0" [package.extras] docs = ["Jinja2 (==2.11.3)", "MarkupSafe (==1.1.1)", "Pygments (==2.8.1)", "alabaster (==0.7.12)", "babel (==2.9.1)", "chardet (==4.0.0)", "commonmark (==0.8.1)", "docutils (==0.17.1)", "future (==0.18.2)", "idna (==2.10)", "imagesize (==1.2.0)", "mock (==1.0.1)", "packaging (==20.9)", "pyparsing (==2.4.7)", "pytz (==2021.1)", "readthedocs-sphinx-ext (==2.1.4)", "recommonmark (==0.5.0)", "requests (==2.25.1)", "six (==1.15.0)", "snowballstemmer (==2.1.0)", "sphinx (==1.8.5)", "sphinx-rtd-theme (==0.4.3)", "sphinxcontrib-serializinghtml (==1.1.4)", "sphinxcontrib-websupport (==1.2.4)", "urllib3 (==1.26.4)"] qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] -testing = ["Django", "attrs", "colorama", "docopt", "pytest (<7.0.0)"] +testing = ["Django", "attrs", "colorama", "docopt", "pytest (<9.0.0)"] [[package]] name = "jmespath" @@ -578,6 +652,7 @@ version = "1.0.1" description = "JSON Matching Expressions" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, @@ -585,71 +660,73 @@ files = [ [[package]] name = "markupsafe" -version = "2.1.5" +version = "3.0.2" description = "Safely add untrusted strings to HTML/XML markup." optional = false -python-versions = ">=3.7" -files = [ - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a17a92de5231666cfbe003f0e4b9b3a7ae3afb1ec2845aadc2bacc93ff85febc"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:72b6be590cc35924b02c78ef34b467da4ba07e4e0f0454a2c5907f473fc50ce5"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e61659ba32cf2cf1481e575d0462554625196a1f2fc06a1c777d3f48e8865d46"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2174c595a0d73a3080ca3257b40096db99799265e1c27cc5a610743acd86d62f"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ae2ad8ae6ebee9d2d94b17fb62763125f3f374c25618198f40cbb8b525411900"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:075202fa5b72c86ad32dc7d0b56024ebdbcf2048c0ba09f1cde31bfdd57bcfff"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:598e3276b64aff0e7b3451b72e94fa3c238d452e7ddcd893c3ab324717456bad"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:fce659a462a1be54d2ffcacea5e3ba2d74daa74f30f5f143fe0c58636e355fdd"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win32.whl", hash = "sha256:d9fad5155d72433c921b782e58892377c44bd6252b5af2f67f16b194987338a4"}, - {file = "MarkupSafe-2.1.5-cp310-cp310-win_amd64.whl", hash = "sha256:bf50cd79a75d181c9181df03572cdce0fbb75cc353bc350712073108cba98de5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:629ddd2ca402ae6dbedfceeba9c46d5f7b2a61d9749597d4307f943ef198fc1f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:5b7b716f97b52c5a14bffdf688f971b2d5ef4029127f1ad7a513973cfd818df2"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ec585f69cec0aa07d945b20805be741395e28ac1627333b1c5b0105962ffced"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b91c037585eba9095565a3556f611e3cbfaa42ca1e865f7b8015fe5c7336d5a5"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7502934a33b54030eaf1194c21c692a534196063db72176b0c4028e140f8f32c"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:0e397ac966fdf721b2c528cf028494e86172b4feba51d65f81ffd65c63798f3f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:c061bb86a71b42465156a3ee7bd58c8c2ceacdbeb95d05a99893e08b8467359a"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:3a57fdd7ce31c7ff06cdfbf31dafa96cc533c21e443d57f5b1ecc6cdc668ec7f"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win32.whl", hash = "sha256:397081c1a0bfb5124355710fe79478cdbeb39626492b15d399526ae53422b906"}, - {file = "MarkupSafe-2.1.5-cp311-cp311-win_amd64.whl", hash = "sha256:2b7c57a4dfc4f16f7142221afe5ba4e093e09e728ca65c51f5620c9aaeb9a617"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:8dec4936e9c3100156f8a2dc89c4b88d5c435175ff03413b443469c7c8c5f4d1"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:3c6b973f22eb18a789b1460b4b91bf04ae3f0c4234a0a6aa6b0a92f6f7b951d4"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ac07bad82163452a6884fe8fa0963fb98c2346ba78d779ec06bd7a6262132aee"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5dfb42c4604dddc8e4305050aa6deb084540643ed5804d7455b5df8fe16f5e5"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ea3d8a3d18833cf4304cd2fc9cbb1efe188ca9b5efef2bdac7adc20594a0e46b"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d050b3361367a06d752db6ead6e7edeb0009be66bc3bae0ee9d97fb326badc2a"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:bec0a414d016ac1a18862a519e54b2fd0fc8bbfd6890376898a6c0891dd82e9f"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:58c98fee265677f63a4385256a6d7683ab1832f3ddd1e66fe948d5880c21a169"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win32.whl", hash = "sha256:8590b4ae07a35970728874632fed7bd57b26b0102df2d2b233b6d9d82f6c62ad"}, - {file = "MarkupSafe-2.1.5-cp312-cp312-win_amd64.whl", hash = "sha256:823b65d8706e32ad2df51ed89496147a42a2a6e01c13cfb6ffb8b1e92bc910bb"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c8b29db45f8fe46ad280a7294f5c3ec36dbac9491f2d1c17345be8e69cc5928f"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec6a563cff360b50eed26f13adc43e61bc0c04d94b8be985e6fb24b81f6dcfdf"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a549b9c31bec33820e885335b451286e2969a2d9e24879f83fe904a5ce59d70a"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4f11aa001c540f62c6166c7726f71f7573b52c68c31f014c25cc7901deea0b52"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:7b2e5a267c855eea6b4283940daa6e88a285f5f2a67f2220203786dfa59b37e9"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2d2d793e36e230fd32babe143b04cec8a8b3eb8a3122d2aceb4a371e6b09b8df"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:ce409136744f6521e39fd8e2a24c53fa18ad67aa5bc7c2cf83645cce5b5c4e50"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win32.whl", hash = "sha256:4096e9de5c6fdf43fb4f04c26fb114f61ef0bf2e5604b6ee3019d51b69e8c371"}, - {file = "MarkupSafe-2.1.5-cp37-cp37m-win_amd64.whl", hash = "sha256:4275d846e41ecefa46e2015117a9f491e57a71ddd59bbead77e904dc02b1bed2"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:656f7526c69fac7f600bd1f400991cc282b417d17539a1b228617081106feb4a"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:97cafb1f3cbcd3fd2b6fbfb99ae11cdb14deea0736fc2b0952ee177f2b813a46"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f3fbcb7ef1f16e48246f704ab79d79da8a46891e2da03f8783a5b6fa41a9532"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa9db3f79de01457b03d4f01b34cf91bc0048eb2c3846ff26f66687c2f6d16ab"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ffee1f21e5ef0d712f9033568f8344d5da8cc2869dbd08d87c84656e6a2d2f68"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5dedb4db619ba5a2787a94d877bc8ffc0566f92a01c0ef214865e54ecc9ee5e0"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:30b600cf0a7ac9234b2638fbc0fb6158ba5bdcdf46aeb631ead21248b9affbc4"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8dd717634f5a044f860435c1d8c16a270ddf0ef8588d4887037c5028b859b0c3"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win32.whl", hash = "sha256:daa4ee5a243f0f20d528d939d06670a298dd39b1ad5f8a72a4275124a7819eff"}, - {file = "MarkupSafe-2.1.5-cp38-cp38-win_amd64.whl", hash = "sha256:619bc166c4f2de5caa5a633b8b7326fbe98e0ccbfacabd87268a2b15ff73a029"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7a68b554d356a91cce1236aa7682dc01df0edba8d043fd1ce607c49dd3c1edcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:db0b55e0f3cc0be60c1f19efdde9a637c32740486004f20d1cff53c3c0ece4d2"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e53af139f8579a6d5f7b76549125f0d94d7e630761a2111bc431fd820e163b8"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:17b950fccb810b3293638215058e432159d2b71005c74371d784862b7e4683f3"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c31f53cdae6ecfa91a77820e8b151dba54ab528ba65dfd235c80b086d68a465"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:bff1b4290a66b490a2f4719358c0cdcd9bafb6b8f061e45c7a2460866bf50c2e"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:bc1667f8b83f48511b94671e0e441401371dfd0f0a795c7daa4a3cd1dde55bea"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5049256f536511ee3f7e1b3f87d1d1209d327e818e6ae1365e8653d7e3abb6a6"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win32.whl", hash = "sha256:00e046b6dd71aa03a41079792f8473dc494d564611a8f89bbbd7cb93295ebdcf"}, - {file = "MarkupSafe-2.1.5-cp39-cp39-win_amd64.whl", hash = "sha256:fa173ec60341d6bb97a89f5ea19c85c5643c1e7dedebc22f5181eb73573142c5"}, - {file = "MarkupSafe-2.1.5.tar.gz", hash = "sha256:d283d37a890ba4c1ae73ffadf8046435c76e7bc2247bbb63c00bd1a709c6544b"}, +python-versions = ">=3.9" +groups = ["main", "dev"] +files = [ + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50"}, + {file = "MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d"}, + {file = "MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30"}, + {file = "MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1"}, + {file = "MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6"}, + {file = "MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:eaa0a10b7f72326f1372a713e73c3f739b524b3af41feb43e4921cb529f5929a"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:48032821bbdf20f5799ff537c7ac3d1fba0ba032cfc06194faffa8cda8b560ff"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1a9d3f5f0901fdec14d8d2f66ef7d035f2157240a433441719ac9a3fba440b13"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88b49a3b9ff31e19998750c38e030fc7bb937398b1f78cfa599aaef92d693144"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cfad01eed2c2e0c01fd0ecd2ef42c492f7f93902e39a42fc9ee1692961443a29"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:1225beacc926f536dc82e45f8a4d68502949dc67eea90eab715dea3a21c1b5f0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:3169b1eefae027567d1ce6ee7cae382c57fe26e82775f460f0b2778beaad66c0"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:eb7972a85c54febfb25b5c4b4f3af4dcc731994c7da0d8a0b4a6eb0640e1d178"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win32.whl", hash = "sha256:8c4e8c3ce11e1f92f6536ff07154f9d49677ebaaafc32db9db4620bc11ed480f"}, + {file = "MarkupSafe-3.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:6e296a513ca3d94054c2c881cc913116e90fd030ad1c656b3869762b754f5f8a"}, + {file = "markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0"}, ] [[package]] @@ -658,6 +735,8 @@ version = "0.1.7" description = "Inline Matplotlib backend for Jupyter" optional = false python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, @@ -668,13 +747,14 @@ traitlets = "*" [[package]] name = "mock" -version = "5.1.0" +version = "5.2.0" description = "Rolling backport of unittest.mock for all Pythons" optional = false python-versions = ">=3.6" +groups = ["dev"] files = [ - {file = "mock-5.1.0-py3-none-any.whl", hash = "sha256:18c694e5ae8a208cdb3d2c20a993ca1a7b0efa258c247a1e565150f477f83744"}, - {file = "mock-5.1.0.tar.gz", hash = "sha256:5e96aad5ccda4718e0a229ed94b2024df75cc2d55575ba5762d31f5767b8767d"}, + {file = "mock-5.2.0-py3-none-any.whl", hash = "sha256:7ba87f72ca0e915175596069dbbcc7c75af7b5e9b9bc107ad6349ede0819982f"}, + {file = "mock-5.2.0.tar.gz", hash = "sha256:4e460e818629b4b173f32d08bf30d3af8123afbb8e04bb5707a1fd4799e503f0"}, ] [package.extras] @@ -684,71 +764,81 @@ test = ["pytest", "pytest-cov"] [[package]] name = "mypy" -version = "1.4.1" +version = "1.17.0" description = "Optional static typing for Python" optional = false -python-versions = ">=3.7" -files = [ - {file = "mypy-1.4.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:566e72b0cd6598503e48ea610e0052d1b8168e60a46e0bfd34b3acf2d57f96a8"}, - {file = "mypy-1.4.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca637024ca67ab24a7fd6f65d280572c3794665eaf5edcc7e90a866544076878"}, - {file = "mypy-1.4.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0dde1d180cd84f0624c5dcaaa89c89775550a675aff96b5848de78fb11adabcd"}, - {file = "mypy-1.4.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8c4d8e89aa7de683e2056a581ce63c46a0c41e31bd2b6d34144e2c80f5ea53dc"}, - {file = "mypy-1.4.1-cp310-cp310-win_amd64.whl", hash = "sha256:bfdca17c36ae01a21274a3c387a63aa1aafe72bff976522886869ef131b937f1"}, - {file = "mypy-1.4.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:7549fbf655e5825d787bbc9ecf6028731973f78088fbca3a1f4145c39ef09462"}, - {file = "mypy-1.4.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:98324ec3ecf12296e6422939e54763faedbfcc502ea4a4c38502082711867258"}, - {file = "mypy-1.4.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:141dedfdbfe8a04142881ff30ce6e6653c9685b354876b12e4fe6c78598b45e2"}, - {file = "mypy-1.4.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:8207b7105829eca6f3d774f64a904190bb2231de91b8b186d21ffd98005f14a7"}, - {file = "mypy-1.4.1-cp311-cp311-win_amd64.whl", hash = "sha256:16f0db5b641ba159eff72cff08edc3875f2b62b2fa2bc24f68c1e7a4e8232d01"}, - {file = "mypy-1.4.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:470c969bb3f9a9efcedbadcd19a74ffb34a25f8e6b0e02dae7c0e71f8372f97b"}, - {file = "mypy-1.4.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5952d2d18b79f7dc25e62e014fe5a23eb1a3d2bc66318df8988a01b1a037c5b"}, - {file = "mypy-1.4.1-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:190b6bab0302cec4e9e6767d3eb66085aef2a1cc98fe04936d8a42ed2ba77bb7"}, - {file = "mypy-1.4.1-cp37-cp37m-win_amd64.whl", hash = "sha256:9d40652cc4fe33871ad3338581dca3297ff5f2213d0df345bcfbde5162abf0c9"}, - {file = "mypy-1.4.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:01fd2e9f85622d981fd9063bfaef1aed6e336eaacca00892cd2d82801ab7c042"}, - {file = "mypy-1.4.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2460a58faeea905aeb1b9b36f5065f2dc9a9c6e4c992a6499a2360c6c74ceca3"}, - {file = "mypy-1.4.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2746d69a8196698146a3dbe29104f9eb6a2a4d8a27878d92169a6c0b74435b6"}, - {file = "mypy-1.4.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:ae704dcfaa180ff7c4cfbad23e74321a2b774f92ca77fd94ce1049175a21c97f"}, - {file = "mypy-1.4.1-cp38-cp38-win_amd64.whl", hash = "sha256:43d24f6437925ce50139a310a64b2ab048cb2d3694c84c71c3f2a1626d8101dc"}, - {file = "mypy-1.4.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:c482e1246726616088532b5e964e39765b6d1520791348e6c9dc3af25b233828"}, - {file = "mypy-1.4.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:43b592511672017f5b1a483527fd2684347fdffc041c9ef53428c8dc530f79a3"}, - {file = "mypy-1.4.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:34a9239d5b3502c17f07fd7c0b2ae6b7dd7d7f6af35fbb5072c6208e76295816"}, - {file = "mypy-1.4.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:5703097c4936bbb9e9bce41478c8d08edd2865e177dc4c52be759f81ee4dd26c"}, - {file = "mypy-1.4.1-cp39-cp39-win_amd64.whl", hash = "sha256:e02d700ec8d9b1859790c0475df4e4092c7bf3272a4fd2c9f33d87fac4427b8f"}, - {file = "mypy-1.4.1-py3-none-any.whl", hash = "sha256:45d32cec14e7b97af848bddd97d85ea4f0db4d5a149ed9676caa4eb2f7402bb4"}, - {file = "mypy-1.4.1.tar.gz", hash = "sha256:9bbcd9ab8ea1f2e1c8031c21445b511442cc45c89951e49bbf852cbb70755b1b"}, +python-versions = ">=3.9" +groups = ["dev"] +files = [ + {file = "mypy-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8e08de6138043108b3b18f09d3f817a4783912e48828ab397ecf183135d84d6"}, + {file = "mypy-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce4a17920ec144647d448fc43725b5873548b1aae6c603225626747ededf582d"}, + {file = "mypy-1.17.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff25d151cc057fdddb1cb1881ef36e9c41fa2a5e78d8dd71bee6e4dcd2bc05b"}, + {file = "mypy-1.17.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93468cf29aa9a132bceb103bd8475f78cacde2b1b9a94fd978d50d4bdf616c9a"}, + {file = "mypy-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98189382b310f16343151f65dd7e6867386d3e35f7878c45cfa11383d175d91f"}, + {file = "mypy-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:c004135a300ab06a045c1c0d8e3f10215e71d7b4f5bb9a42ab80236364429937"}, + {file = "mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be"}, + {file = "mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61"}, + {file = "mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f"}, + {file = "mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d"}, + {file = "mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3"}, + {file = "mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70"}, + {file = "mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb"}, + {file = "mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d"}, + {file = "mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8"}, + {file = "mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e"}, + {file = "mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8"}, + {file = "mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d"}, + {file = "mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06"}, + {file = "mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a"}, + {file = "mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889"}, + {file = "mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba"}, + {file = "mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658"}, + {file = "mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c"}, + {file = "mypy-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63e751f1b5ab51d6f3d219fe3a2fe4523eaa387d854ad06906c63883fde5b1ab"}, + {file = "mypy-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fb09d05e0f1c329a36dcd30e27564a3555717cde87301fae4fb542402ddfad"}, + {file = "mypy-1.17.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b72c34ce05ac3a1361ae2ebb50757fb6e3624032d91488d93544e9f82db0ed6c"}, + {file = "mypy-1.17.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434ad499ad8dde8b2f6391ddfa982f41cb07ccda8e3c67781b1bfd4e5f9450a8"}, + {file = "mypy-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f105f61a5eff52e137fd73bee32958b2add9d9f0a856f17314018646af838e97"}, + {file = "mypy-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:ba06254a5a22729853209550d80f94e28690d5530c661f9416a68ac097b13fc4"}, + {file = "mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496"}, + {file = "mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03"}, ] [package.dependencies] -mypy-extensions = ">=1.0.0" +mypy_extensions = ">=1.0.0" +pathspec = ">=0.9.0" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} -typed-ast = {version = ">=1.4.0,<2", markers = "python_version < \"3.8\""} -typing-extensions = ">=4.1.0" +typing_extensions = ">=4.6.0" [package.extras] dmypy = ["psutil (>=4.0)"] +faster-cache = ["orjson"] install-types = ["pip"] -python2 = ["typed-ast (>=1.4.0,<2)"] +mypyc = ["setuptools (>=50)"] reports = ["lxml"] [[package]] name = "mypy-extensions" -version = "1.0.0" +version = "1.1.0" description = "Type system extensions for programs checked with the mypy type checker." optional = false -python-versions = ">=3.5" +python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"}, - {file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"}, + {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 = "packaging" -version = "24.0" +version = "25.0" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "packaging-24.0-py3-none-any.whl", hash = "sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5"}, - {file = "packaging-24.0.tar.gz", hash = "sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9"}, + {file = "packaging-25.0-py3-none-any.whl", hash = "sha256:29572ef2b1f17581046b3a2227d5c611fb25ec70ca1ba8554b24b0e69331a484"}, + {file = "packaging-25.0.tar.gz", hash = "sha256:d443872c98d677bf60f6a1f2f8c1cb748e8fe762d2bf9d3148b5599295b0fc4f"}, ] [[package]] @@ -757,6 +847,8 @@ version = "0.8.4" description = "A Python Parser" optional = false python-versions = ">=3.6" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, @@ -766,23 +858,13 @@ files = [ qa = ["flake8 (==5.0.4)", "mypy (==0.971)", "types-setuptools (==67.2.0.1)"] testing = ["docopt", "pytest"] -[[package]] -name = "pathspec" -version = "0.11.2" -description = "Utility library for gitignore style pattern matching of file paths." -optional = false -python-versions = ">=3.7" -files = [ - {file = "pathspec-0.11.2-py3-none-any.whl", hash = "sha256:1d6ed233af05e679efb96b1851550ea95bbb64b7c490b0f5aa52996c11e92a20"}, - {file = "pathspec-0.11.2.tar.gz", hash = "sha256:e0d8d0ac2f12da61956eb2306b69f9469b42f4deb0f3cb6ed47b9cce9996ced3"}, -] - [[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 = ["dev"] files = [ {file = "pathspec-0.12.1-py3-none-any.whl", hash = "sha256:a0d503e138a4c123b27490a4f7beda6a01c6f288df0e4a8b79c7eb0dc7b4cc08"}, {file = "pathspec-0.12.1.tar.gz", hash = "sha256:a482d51503a1ab33b1c67a6c3813a26953dbdc71c31dacaef9a838c4e29f5712"}, @@ -794,6 +876,8 @@ version = "4.9.0" description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" +groups = ["local"] +markers = "python_version == \"3.9\" and sys_platform != \"win32\" or python_version < \"4.0\" and sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, @@ -804,49 +888,48 @@ ptyprocess = ">=0.5" [[package]] name = "platformdirs" -version = "4.0.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.8" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "platformdirs-4.0.0-py3-none-any.whl", hash = "sha256:118c954d7e949b35437270383a3f2531e99dd93cf7ce4dc8340d3356d30f173b"}, - {file = "platformdirs-4.0.0.tar.gz", hash = "sha256:cb633b2bcf10c51af60beb0ab06d2f1d69064b43abf4c185ca6b28865f3f9731"}, + {file = "platformdirs-4.3.8-py3-none-any.whl", hash = "sha256:ff7059bb7eb1179e2685604f4aaf157cfd9535242bd23742eadc3c13542139b4"}, + {file = "platformdirs-4.3.8.tar.gz", hash = "sha256:3d512d96e16bcb959a814c9f348431070822a6496326a4be0911c40b5a74c2bc"}, ] -[package.dependencies] -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} - [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +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.2.0" +version = "1.6.0" description = "plugin and hook calling mechanisms for python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "pluggy-1.2.0-py3-none-any.whl", hash = "sha256:c2fd55a7d7a3863cba1a013e4e2414658b1d07b6bc57b3919e0c63c9abb99849"}, - {file = "pluggy-1.2.0.tar.gz", hash = "sha256:d12f0c4b579b15f5e054301bb226ee85eeeba08ffec228092f8defbaa3a4c4b3"}, + {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, + {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, ] -[package.dependencies] -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} - [package.extras] dev = ["pre-commit", "tox"] -testing = ["pytest", "pytest-benchmark"] +testing = ["coverage", "pytest", "pytest-benchmark"] [[package]] name = "prompt-toolkit" -version = "3.0.47" +version = "3.0.51" description = "Library for building powerful interactive command lines in Python" optional = false -python-versions = ">=3.7.0" +python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "prompt_toolkit-3.0.47-py3-none-any.whl", hash = "sha256:0d7bfa67001d5e39d02c224b663abc33687405033a8c422d0d675a5a13361d10"}, - {file = "prompt_toolkit-3.0.47.tar.gz", hash = "sha256:1e1b29cb58080b1e69f207c893a1a7bf16d127a5c30c9d17a25a5d77792e5360"}, + {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, + {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, ] [package.dependencies] @@ -858,6 +941,8 @@ version = "0.7.0" description = "Run a subprocess in a pseudo terminal" optional = false python-versions = "*" +groups = ["local"] +markers = "python_version == \"3.9\" and sys_platform != \"win32\" or python_version < \"4.0\" and sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -869,6 +954,8 @@ version = "0.2.3" description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, @@ -879,13 +966,15 @@ tests = ["pytest"] [[package]] name = "pygments" -version = "2.18.0" +version = "2.19.2" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ - {file = "pygments-2.18.0-py3-none-any.whl", hash = "sha256:b8e6aca0523f3ab76fee51799c488e38782ac06eafcf95e7ba832985c8e7b13a"}, - {file = "pygments-2.18.0.tar.gz", hash = "sha256:786ff802f32e91311bff3889f6e9a86e81505fe99f2735bb6d60ae0c5004f199"}, + {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, + {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, ] [package.extras] @@ -893,32 +982,34 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyproject-api" -version = "1.5.3" +version = "1.9.1" description = "API to interact with the python pyproject.toml based projects" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "pyproject_api-1.5.3-py3-none-any.whl", hash = "sha256:14cf09828670c7b08842249c1f28c8ee6581b872e893f81b62d5465bec41502f"}, - {file = "pyproject_api-1.5.3.tar.gz", hash = "sha256:ffb5b2d7cad43f5b2688ab490de7c4d3f6f15e0b819cb588c4b771567c9729eb"}, + {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 = ">=23.1" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} +packaging = ">=25" +tomli = {version = ">=2.2.1", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-autodoc-typehints (>=1.23,!=1.23.4)"] -testing = ["covdefaults (>=2.3)", "importlib-metadata (>=6.6)", "pytest (>=7.3.1)", "pytest-cov (>=4.1)", "pytest-mock (>=3.10)", "setuptools (>=67.8)", "wheel (>=0.40)"] +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.1.0" +version = "1.2.0" description = "Wrappers to call pyproject.toml-based build backend hooks." optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ - {file = "pyproject_hooks-1.1.0-py3-none-any.whl", hash = "sha256:7ceeefe9aec63a1064c18d939bdc3adf2d8aa1988a510afec15151578b232aa2"}, - {file = "pyproject_hooks-1.1.0.tar.gz", hash = "sha256:4b37730834edbd6bd37f26ece6b44802fb1c1ee2ece0e54ddff8bfc06db86965"}, + {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]] @@ -927,6 +1018,7 @@ version = "7.4.4" description = "pytest: simple powerful testing with Python" optional = false python-versions = ">=3.7" +groups = ["dev"] files = [ {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, @@ -935,7 +1027,6 @@ files = [ [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} -importlib-metadata = {version = ">=0.12", markers = "python_version < \"3.8\""} iniconfig = "*" packaging = "*" pluggy = ">=0.12,<2.0" @@ -946,13 +1037,15 @@ testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "no [[package]] name = "pytest-httpserver" -version = "1.1.0" +version = "1.1.3" description = "pytest-httpserver is a httpserver for pytest" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version < \"4.0\"" files = [ - {file = "pytest_httpserver-1.1.0-py3-none-any.whl", hash = "sha256:7ef88be8ed3354b6784daa3daa75a422370327c634053cefb124903fa8d73a41"}, - {file = "pytest_httpserver-1.1.0.tar.gz", hash = "sha256:6b1cb0199e2ed551b1b94d43f096863bbf6ae5bcd7c75c2c06845e5ce2dc8701"}, + {file = "pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9"}, + {file = "pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec"}, ] [package.dependencies] @@ -964,6 +1057,7 @@ version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -974,39 +1068,19 @@ six = ">=1.5" [[package]] name = "requests" -version = "2.31.0" -description = "Python HTTP for Humans." -optional = false -python-versions = ">=3.7" -files = [ - {file = "requests-2.31.0-py3-none-any.whl", hash = "sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f"}, - {file = "requests-2.31.0.tar.gz", hash = "sha256:942c5a758f98d790eaed1a29cb6eefc7ffb0d1cf7af05c3d2791656dbd6ad1e1"}, -] - -[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" -version = "2.32.3" +version = "2.32.4" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" +groups = ["main"] files = [ - {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, - {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, + {file = "requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c"}, + {file = "requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422"}, ] [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = ">=2,<4" +charset_normalizer = ">=2,<4" idna = ">=2.5,<4" urllib3 = ">=1.21.1,<3" @@ -1016,57 +1090,60 @@ use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] name = "ruff" -version = "0.6.2" +version = "0.12.7" description = "An extremely fast Python linter and code formatter, written in Rust." optional = false python-versions = ">=3.7" -files = [ - {file = "ruff-0.6.2-py3-none-linux_armv6l.whl", hash = "sha256:5c8cbc6252deb3ea840ad6a20b0f8583caab0c5ef4f9cca21adc5a92b8f79f3c"}, - {file = "ruff-0.6.2-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:17002fe241e76544448a8e1e6118abecbe8cd10cf68fde635dad480dba594570"}, - {file = "ruff-0.6.2-py3-none-macosx_11_0_arm64.whl", hash = "sha256:3dbeac76ed13456f8158b8f4fe087bf87882e645c8e8b606dd17b0b66c2c1158"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:094600ee88cda325988d3f54e3588c46de5c18dae09d683ace278b11f9d4d534"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:316d418fe258c036ba05fbf7dfc1f7d3d4096db63431546163b472285668132b"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d72b8b3abf8a2d51b7b9944a41307d2f442558ccb3859bbd87e6ae9be1694a5d"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:2aed7e243be68487aa8982e91c6e260982d00da3f38955873aecd5a9204b1d66"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d371f7fc9cec83497fe7cf5eaf5b76e22a8efce463de5f775a1826197feb9df8"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8f310d63af08f583363dfb844ba8f9417b558199c58a5999215082036d795a1"}, - {file = "ruff-0.6.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7db6880c53c56addb8638fe444818183385ec85eeada1d48fc5abe045301b2f1"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:1175d39faadd9a50718f478d23bfc1d4da5743f1ab56af81a2b6caf0a2394f23"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:5b939f9c86d51635fe486585389f54582f0d65b8238e08c327c1534844b3bb9a"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_i686.whl", hash = "sha256:d0d62ca91219f906caf9b187dea50d17353f15ec9bb15aae4a606cd697b49b4c"}, - {file = "ruff-0.6.2-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:7438a7288f9d67ed3c8ce4d059e67f7ed65e9fe3aa2ab6f5b4b3610e57e3cb56"}, - {file = "ruff-0.6.2-py3-none-win32.whl", hash = "sha256:279d5f7d86696df5f9549b56b9b6a7f6c72961b619022b5b7999b15db392a4da"}, - {file = "ruff-0.6.2-py3-none-win_amd64.whl", hash = "sha256:d9f3469c7dd43cd22eb1c3fc16926fb8258d50cb1b216658a07be95dd117b0f2"}, - {file = "ruff-0.6.2-py3-none-win_arm64.whl", hash = "sha256:f28fcd2cd0e02bdf739297516d5643a945cc7caf09bd9bcb4d932540a5ea4fa9"}, - {file = "ruff-0.6.2.tar.gz", hash = "sha256:239ee6beb9e91feb8e0ec384204a763f36cb53fb895a1a364618c6abb076b3be"}, +groups = ["dev"] +files = [ + {file = "ruff-0.12.7-py3-none-linux_armv6l.whl", hash = "sha256:76e4f31529899b8c434c3c1dede98c4483b89590e15fb49f2d46183801565303"}, + {file = "ruff-0.12.7-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:789b7a03e72507c54fb3ba6209e4bb36517b90f1a3569ea17084e3fd295500fb"}, + {file = "ruff-0.12.7-py3-none-macosx_11_0_arm64.whl", hash = "sha256:2e1c2a3b8626339bb6369116e7030a4cf194ea48f49b64bb505732a7fce4f4e3"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:32dec41817623d388e645612ec70d5757a6d9c035f3744a52c7b195a57e03860"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47ef751f722053a5df5fa48d412dbb54d41ab9b17875c6840a58ec63ff0c247c"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a828a5fc25a3efd3e1ff7b241fd392686c9386f20e5ac90aa9234a5faa12c423"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:5726f59b171111fa6a69d82aef48f00b56598b03a22f0f4170664ff4d8298efb"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:74e6f5c04c4dd4aba223f4fe6e7104f79e0eebf7d307e4f9b18c18362124bccd"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5d0bfe4e77fba61bf2ccadf8cf005d6133e3ce08793bbe870dd1c734f2699a3e"}, + {file = "ruff-0.12.7-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:06bfb01e1623bf7f59ea749a841da56f8f653d641bfd046edee32ede7ff6c606"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:e41df94a957d50083fd09b916d6e89e497246698c3f3d5c681c8b3e7b9bb4ac8"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:4000623300563c709458d0ce170c3d0d788c23a058912f28bbadc6f905d67afa"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_i686.whl", hash = "sha256:69ffe0e5f9b2cf2b8e289a3f8945b402a1b19eff24ec389f45f23c42a3dd6fb5"}, + {file = "ruff-0.12.7-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:a07a5c8ffa2611a52732bdc67bf88e243abd84fe2d7f6daef3826b59abbfeda4"}, + {file = "ruff-0.12.7-py3-none-win32.whl", hash = "sha256:c928f1b2ec59fb77dfdf70e0419408898b63998789cc98197e15f560b9e77f77"}, + {file = "ruff-0.12.7-py3-none-win_amd64.whl", hash = "sha256:9c18f3d707ee9edf89da76131956aba1270c6348bfee8f6c647de841eac7194f"}, + {file = "ruff-0.12.7-py3-none-win_arm64.whl", hash = "sha256:dfce05101dbd11833a0776716d5d1578641b7fddb537fe7fa956ab85d1769b69"}, + {file = "ruff-0.12.7.tar.gz", hash = "sha256:1fc3193f238bc2d7968772c82831a4ff69252f673be371fb49663f0068b7ec71"}, ] [[package]] name = "s3transfer" -version = "0.8.2" +version = "0.13.1" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "s3transfer-0.8.2-py3-none-any.whl", hash = "sha256:c9e56cbe88b28d8e197cf841f1f0c130f246595e77ae5b5a05b69fe7cb83de76"}, - {file = "s3transfer-0.8.2.tar.gz", hash = "sha256:368ac6876a9e9ed91f6bc86581e319be08188dc60d50e0d56308ed5765446283"}, + {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, + {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, ] [package.dependencies] -botocore = ">=1.33.2,<2.0a.0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.33.2,<2.0a.0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "six" -version = "1.16.0" +version = "1.17.0" description = "Python 2 and 3 compatibility utilities" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" +groups = ["dev"] files = [ - {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, - {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, + {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, + {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, ] [[package]] @@ -1075,6 +1152,8 @@ version = "0.6.3" description = "Extract data from python stack frames and tracebacks for informative displays" optional = false python-versions = "*" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, @@ -1094,6 +1173,7 @@ version = "0.10.2" description = "Python Library for Tom's Obvious, Minimal Language" optional = false python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +groups = ["dev"] files = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, @@ -1101,43 +1181,71 @@ files = [ [[package]] name = "tomli" -version = "2.0.1" +version = "2.2.1" description = "A lil' TOML parser" optional = false -python-versions = ">=3.7" -files = [ - {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, - {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +python-versions = ">=3.8" +groups = ["dev"] +markers = "python_version < \"3.11\"" +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"}, ] [[package]] name = "tox" -version = "4.8.0" +version = "4.28.3" description = "tox is a generic virtualenv management and test command line tool" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "tox-4.8.0-py3-none-any.whl", hash = "sha256:4991305a56983d750a0d848a34242be290452aa88d248f1bf976e4036ee8b213"}, - {file = "tox-4.8.0.tar.gz", hash = "sha256:2adacf435b12ccf10b9dfa9975d8ec0afd7cbae44d300463140d2117b968037b"}, + {file = "tox-4.28.3-py3-none-any.whl", hash = "sha256:1debe9daf0b7e64d425ef99a17292b0792385686b1d541df34c7298211e99269"}, + {file = "tox-4.28.3.tar.gz", hash = "sha256:b91db7219e5242002cf4040a299c8852026d6af35fcd21274d456fb62dafee7b"}, ] [package.dependencies] -cachetools = ">=5.3.1" -chardet = ">=5.1" +cachetools = ">=6.1" +chardet = ">=5.2" colorama = ">=0.4.6" -filelock = ">=3.12.2" -importlib-metadata = {version = ">=6.7", markers = "python_version < \"3.8\""} -packaging = ">=23.1" -platformdirs = ">=3.9.1" -pluggy = ">=1.2" -pyproject-api = ">=1.5.3" -tomli = {version = ">=2.0.1", markers = "python_version < \"3.11\""} -typing-extensions = {version = ">=4.7.1", markers = "python_version < \"3.8\""} -virtualenv = ">=20.24.1" - -[package.extras] -docs = ["furo (>=2023.5.20)", "sphinx (>=7.0.1)", "sphinx-argparse-cli (>=1.11.1)", "sphinx-autodoc-typehints (>=1.23.3,!=1.23.4)", "sphinx-copybutton (>=0.5.2)", "sphinx-inline-tabs (>=2023.4.21)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] -testing = ["build[virtualenv] (>=0.10)", "covdefaults (>=2.3)", "detect-test-pollution (>=1.1.1)", "devpi-process (>=0.3.1)", "diff-cover (>=7.7)", "distlib (>=0.3.7)", "flaky (>=3.7)", "hatch-vcs (>=0.3)", "hatchling (>=1.17.1)", "psutil (>=5.9.5)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)", "pytest-xdist (>=3.3.1)", "re-assert (>=1.1)", "time-machine (>=2.10)", "wheel (>=0.40)"] +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 = "traitlets" @@ -1145,6 +1253,8 @@ version = "5.14.3" description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, @@ -1154,65 +1264,16 @@ files = [ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0,<8.2)", "pytest-mock", "pytest-mypy-testing"] -[[package]] -name = "typed-ast" -version = "1.5.5" -description = "a fork of Python 2 and 3 ast modules with type comment support" -optional = false -python-versions = ">=3.6" -files = [ - {file = "typed_ast-1.5.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4bc1efe0ce3ffb74784e06460f01a223ac1f6ab31c6bc0376a21184bf5aabe3b"}, - {file = "typed_ast-1.5.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5f7a8c46a8b333f71abd61d7ab9255440d4a588f34a21f126bbfc95f6049e686"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:597fc66b4162f959ee6a96b978c0435bd63791e31e4f410622d19f1686d5e769"}, - {file = "typed_ast-1.5.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d41b7a686ce653e06c2609075d397ebd5b969d821b9797d029fccd71fdec8e04"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:5fe83a9a44c4ce67c796a1b466c270c1272e176603d5e06f6afbc101a572859d"}, - {file = "typed_ast-1.5.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:d5c0c112a74c0e5db2c75882a0adf3133adedcdbfd8cf7c9d6ed77365ab90a1d"}, - {file = "typed_ast-1.5.5-cp310-cp310-win_amd64.whl", hash = "sha256:e1a976ed4cc2d71bb073e1b2a250892a6e968ff02aa14c1f40eba4f365ffec02"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c631da9710271cb67b08bd3f3813b7af7f4c69c319b75475436fcab8c3d21bee"}, - {file = "typed_ast-1.5.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:b445c2abfecab89a932b20bd8261488d574591173d07827c1eda32c457358b18"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc95ffaaab2be3b25eb938779e43f513e0e538a84dd14a5d844b8f2932593d88"}, - {file = "typed_ast-1.5.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61443214d9b4c660dcf4b5307f15c12cb30bdfe9588ce6158f4a005baeb167b2"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:6eb936d107e4d474940469e8ec5b380c9b329b5f08b78282d46baeebd3692dc9"}, - {file = "typed_ast-1.5.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e48bf27022897577d8479eaed64701ecaf0467182448bd95759883300ca818c8"}, - {file = "typed_ast-1.5.5-cp311-cp311-win_amd64.whl", hash = "sha256:83509f9324011c9a39faaef0922c6f720f9623afe3fe220b6d0b15638247206b"}, - {file = "typed_ast-1.5.5-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:44f214394fc1af23ca6d4e9e744804d890045d1643dd7e8229951e0ef39429b5"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:118c1ce46ce58fda78503eae14b7664163aa735b620b64b5b725453696f2a35c"}, - {file = "typed_ast-1.5.5-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:be4919b808efa61101456e87f2d4c75b228f4e52618621c77f1ddcaae15904fa"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fc2b8c4e1bc5cd96c1a823a885e6b158f8451cf6f5530e1829390b4d27d0807f"}, - {file = "typed_ast-1.5.5-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:16f7313e0a08c7de57f2998c85e2a69a642e97cb32f87eb65fbfe88381a5e44d"}, - {file = "typed_ast-1.5.5-cp36-cp36m-win_amd64.whl", hash = "sha256:2b946ef8c04f77230489f75b4b5a4a6f24c078be4aed241cfabe9cbf4156e7e5"}, - {file = "typed_ast-1.5.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2188bc33d85951ea4ddad55d2b35598b2709d122c11c75cffd529fbc9965508e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0635900d16ae133cab3b26c607586131269f88266954eb04ec31535c9a12ef1e"}, - {file = "typed_ast-1.5.5-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:57bfc3cf35a0f2fdf0a88a3044aafaec1d2f24d8ae8cd87c4f58d615fb5b6311"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:fe58ef6a764de7b4b36edfc8592641f56e69b7163bba9f9c8089838ee596bfb2"}, - {file = "typed_ast-1.5.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:d09d930c2d1d621f717bb217bf1fe2584616febb5138d9b3e8cdd26506c3f6d4"}, - {file = "typed_ast-1.5.5-cp37-cp37m-win_amd64.whl", hash = "sha256:d40c10326893ecab8a80a53039164a224984339b2c32a6baf55ecbd5b1df6431"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:fd946abf3c31fb50eee07451a6aedbfff912fcd13cf357363f5b4e834cc5e71a"}, - {file = "typed_ast-1.5.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:ed4a1a42df8a3dfb6b40c3d2de109e935949f2f66b19703eafade03173f8f437"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:045f9930a1550d9352464e5149710d56a2aed23a2ffe78946478f7b5416f1ede"}, - {file = "typed_ast-1.5.5-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:381eed9c95484ceef5ced626355fdc0765ab51d8553fec08661dce654a935db4"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:bfd39a41c0ef6f31684daff53befddae608f9daf6957140228a08e51f312d7e6"}, - {file = "typed_ast-1.5.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8c524eb3024edcc04e288db9541fe1f438f82d281e591c548903d5b77ad1ddd4"}, - {file = "typed_ast-1.5.5-cp38-cp38-win_amd64.whl", hash = "sha256:7f58fabdde8dcbe764cef5e1a7fcb440f2463c1bbbec1cf2a86ca7bc1f95184b"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:042eb665ff6bf020dd2243307d11ed626306b82812aba21836096d229fdc6a10"}, - {file = "typed_ast-1.5.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:622e4a006472b05cf6ef7f9f2636edc51bda670b7bbffa18d26b255269d3d814"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1efebbbf4604ad1283e963e8915daa240cb4bf5067053cf2f0baadc4d4fb51b8"}, - {file = "typed_ast-1.5.5-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f0aefdd66f1784c58f65b502b6cf8b121544680456d1cebbd300c2c813899274"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:48074261a842acf825af1968cd912f6f21357316080ebaca5f19abbb11690c8a"}, - {file = "typed_ast-1.5.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:429ae404f69dc94b9361bb62291885894b7c6fb4640d561179548c849f8492ba"}, - {file = "typed_ast-1.5.5-cp39-cp39-win_amd64.whl", hash = "sha256:335f22ccb244da2b5c296e6f96b06ee9bed46526db0de38d2f0e5a6597b81155"}, - {file = "typed_ast-1.5.5.tar.gz", hash = "sha256:94282f7a354f36ef5dbce0ef3467ebf6a258e370ab33d5b40c249fa996e590dd"}, -] - [[package]] name = "types-mock" -version = "5.1.0.3" +version = "5.2.0.20250516" description = "Typing stubs for mock" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "types-mock-5.1.0.3.tar.gz", hash = "sha256:eeeac25480287bb721fb17fcda2e9768d70a476dcc14a2c1d0389535c54f8184"}, - {file = "types_mock-5.1.0.3-py3-none-any.whl", hash = "sha256:e5821fdfd57bd545b101dc42373b0112027a1e53e82afbd801c122840b3a2780"}, + {file = "types_mock-5.2.0.20250516-py3-none-any.whl", hash = "sha256:e50fbd0c3be8bcea25c30a47fac0b7a6ca22f630ef2f53416a73b319b39dfde1"}, + {file = "types_mock-5.2.0.20250516.tar.gz", hash = "sha256:aab7d3d9ad3814f2f8da12cc8e42d9be7d38200c5f214e3c0278c38fa01299d7"}, ] [[package]] @@ -1221,6 +1282,8 @@ version = "2.31.0.6" description = "Typing stubs for requests" optional = false python-versions = ">=3.7" +groups = ["dev"] +markers = "python_version == \"3.9\"" files = [ {file = "types-requests-2.31.0.6.tar.gz", hash = "sha256:cd74ce3b53c461f1228a9b783929ac73a666658f223e28ed29753771477b3bd0"}, {file = "types_requests-2.31.0.6-py3-none-any.whl", hash = "sha256:a2db9cb228a81da8348b49ad6db3f5519452dd20a9c1e1a868c83c5fe88fd1a9"}, @@ -1231,13 +1294,15 @@ types-urllib3 = "*" [[package]] name = "types-requests" -version = "2.31.0.20231231" +version = "2.32.4.20250611" description = "Typing stubs for requests" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version >= \"3.10\"" files = [ - {file = "types-requests-2.31.0.20231231.tar.gz", hash = "sha256:0f8c0c9764773384122813548d9eea92a5c4e1f33ed54556b508968ec5065cee"}, - {file = "types_requests-2.31.0.20231231-py3-none-any.whl", hash = "sha256:2e2230c7bc8dd63fa3153c1c0ae335f8a368447f0582fc332f17d54f88e69027"}, + {file = "types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072"}, + {file = "types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826"}, ] [package.dependencies] @@ -1249,6 +1314,7 @@ version = "73.0.0.20240822" description = "Typing stubs for setuptools" optional = false python-versions = ">=3.8" +groups = ["dev"] files = [ {file = "types-setuptools-73.0.0.20240822.tar.gz", hash = "sha256:3a060681098eb3fbc2fea0a86f7f6af6aa1ca71906039d88d891ea2cecdd4dbf"}, {file = "types_setuptools-73.0.0.20240822-py3-none-any.whl", hash = "sha256:b9eba9b68546031317a0fa506d4973641d987d74f79e7dd8369ad4f7a93dea17"}, @@ -1256,13 +1322,14 @@ files = [ [[package]] name = "types-six" -version = "1.16.21.9" +version = "1.17.0.20250515" description = "Typing stubs for six" optional = false -python-versions = "*" +python-versions = ">=3.9" +groups = ["dev"] files = [ - {file = "types-six-1.16.21.9.tar.gz", hash = "sha256:746e6c25b8c48b3c8ab9efe7f68022839111de423d35ba4b206b88b12d75f233"}, - {file = "types_six-1.16.21.9-py3-none-any.whl", hash = "sha256:1591a09430a3035326da5fdb71692d0b3cc36b25a440cc5929ca6241f3984705"}, + {file = "types_six-1.17.0.20250515-py3-none-any.whl", hash = "sha256:adfaa9568caf35e03d80ffa4ed765c33b282579c869b40bf4b6009c7d8db3fb1"}, + {file = "types_six-1.17.0.20250515.tar.gz", hash = "sha256:f4f7f0398cb79304e88397336e642b15e96fbeacf5b96d7625da366b069d2d18"}, ] [[package]] @@ -1271,6 +1338,8 @@ version = "1.26.25.14" description = "Typing stubs for urllib3" optional = false python-versions = "*" +groups = ["dev"] +markers = "python_version == \"3.9\"" files = [ {file = "types-urllib3-1.26.25.14.tar.gz", hash = "sha256:229b7f577c951b8c1b92c1bc2b2fdb0b49847bd2af6d1cc2a2e3dd340f3bda8f"}, {file = "types_urllib3-1.26.25.14-py3-none-any.whl", hash = "sha256:9683bbb7fb72e32bfe9d2be6e04875fbe1b3eeec3cbb4ea231435aa7fd6b4f0e"}, @@ -1278,68 +1347,74 @@ files = [ [[package]] name = "typing-extensions" -version = "4.7.1" -description = "Backported and Experimental Type Hints for Python 3.7+" +version = "4.14.1" +description = "Backported and Experimental Type Hints for Python 3.9+" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev", "local"] files = [ - {file = "typing_extensions-4.7.1-py3-none-any.whl", hash = "sha256:440d5dd3af93b060174bf433bccd69b0babc3b15b1a8dca43789fd7f61514b36"}, - {file = "typing_extensions-4.7.1.tar.gz", hash = "sha256:b75ddc264f0ba5615db7ba217daeb99701ad295353c45f9e95963337ceeeffb2"}, + {file = "typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76"}, + {file = "typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36"}, ] +markers = {local = "python_version < \"3.12\""} [[package]] name = "urllib3" -version = "1.26.19" +version = "1.26.20" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,>=2.7" +groups = ["main", "dev"] +markers = "python_version == \"3.9\"" files = [ - {file = "urllib3-1.26.19-py2.py3-none-any.whl", hash = "sha256:37a0344459b199fce0e80b0d3569837ec6b6937435c5244e7fd73fa6006830f3"}, - {file = "urllib3-1.26.19.tar.gz", hash = "sha256:3e3d753a8618b86d7de333b4223005f68720bcd6a7d2bcb9fbd2229ec7c1e429"}, + {file = "urllib3-1.26.20-py2.py3-none-any.whl", hash = "sha256:0ed14ccfbf1c30a9072c7ca157e4319b70d65f623e91e7b32fadb2853431016e"}, + {file = "urllib3-1.26.20.tar.gz", hash = "sha256:40c2dc0c681e47eb8f90e7e27bf6ff7df2e677421fd46756da1161c39ca70d32"}, ] [package.extras] -brotli = ["brotli (==1.0.9)", "brotli (>=1.0.9)", "brotlicffi (>=0.8.0)", "brotlipy (>=0.6.0)"] -secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] +brotli = ["brotli (==1.0.9) ; os_name != \"nt\" and python_version < \"3\" and platform_python_implementation == \"CPython\"", "brotli (>=1.0.9) ; python_version >= \"3\" and platform_python_implementation == \"CPython\"", "brotlicffi (>=0.8.0) ; (os_name != \"nt\" or python_version >= \"3\") and platform_python_implementation != \"CPython\"", "brotlipy (>=0.6.0) ; os_name == \"nt\" and python_version < \"3\""] +secure = ["certifi", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "ipaddress ; python_version == \"2.7\"", "pyOpenSSL (>=0.14)", "urllib3-secure-extra"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [[package]] name = "urllib3" -version = "2.0.7" +version = "2.5.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["main", "dev"] +markers = "python_version >= \"3.10\"" files = [ - {file = "urllib3-2.0.7-py3-none-any.whl", hash = "sha256:fdb6d215c776278489906c2f8916e6e7d4f5a9b602ccbcfdf7f016fc8da0596e"}, - {file = "urllib3-2.0.7.tar.gz", hash = "sha256:c97dfde1f7bd43a71c8d2a58e369e9b2bf692d1334ea9f9cae55add7d0dd0f84"}, + {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)", "brotlicffi (>=0.8.0)"] -secure = ["certifi", "cryptography (>=1.9)", "idna (>=2.0.0)", "pyopenssl (>=17.1.0)", "urllib3-secure-extra"] +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.26.3" +version = "20.32.0" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" +groups = ["dev"] files = [ - {file = "virtualenv-20.26.3-py3-none-any.whl", hash = "sha256:8cc4a31139e796e9a7de2cd5cf2489de1217193116a8fd42328f1bd65f434589"}, - {file = "virtualenv-20.26.3.tar.gz", hash = "sha256:4c43a2a236279d9ea36a0d76f98d84bd6ca94ac4e0f4a3b9d46d05e10fea542a"}, + {file = "virtualenv-20.32.0-py3-none-any.whl", hash = "sha256:2c310aecb62e5aa1b06103ed7c2977b81e042695de2697d01017ff0f1034af56"}, + {file = "virtualenv-20.32.0.tar.gz", hash = "sha256:886bf75cadfdc964674e6e33eb74d787dff31ca314ceace03ca5810620f4ecf0"}, ] [package.dependencies] distlib = ">=0.3.7,<1" filelock = ">=3.12.2,<4" -importlib-metadata = {version = ">=6.6", markers = "python_version < \"3.8\""} platformdirs = ">=3.9.1,<5" [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)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] +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 = "wcwidth" @@ -1347,6 +1422,8 @@ version = "0.2.13" description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" +groups = ["local"] +markers = "python_version < \"4.0\"" files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -1354,30 +1431,14 @@ files = [ [[package]] name = "werkzeug" -version = "2.2.3" +version = "3.1.3" description = "The comprehensive WSGI web application library." optional = false -python-versions = ">=3.7" -files = [ - {file = "Werkzeug-2.2.3-py3-none-any.whl", hash = "sha256:56433961bc1f12533306c624f3be5e744389ac61d722175d543e1751285da612"}, - {file = "Werkzeug-2.2.3.tar.gz", hash = "sha256:2e1ccc9417d4da358b9de6f174e3ac094391ea1d4fbef2d667865d819dfd0afe"}, -] - -[package.dependencies] -MarkupSafe = ">=2.1.1" - -[package.extras] -watchdog = ["watchdog"] - -[[package]] -name = "werkzeug" -version = "3.0.4" -description = "The comprehensive WSGI web application library." -optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" +groups = ["main", "dev"] files = [ - {file = "werkzeug-3.0.4-py3-none-any.whl", hash = "sha256:02c9eb92b7d6c06f31a782811505d2157837cea66aaede3e217c7c27c039476c"}, - {file = "werkzeug-3.0.4.tar.gz", hash = "sha256:34f2371506b250df4d4f84bfe7b0921e4762525762bbd936614909fe25cd7306"}, + {file = "werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e"}, + {file = "werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746"}, ] [package.dependencies] @@ -1388,20 +1449,26 @@ watchdog = ["watchdog (>=2.3)"] [[package]] name = "zipp" -version = "3.15.0" +version = "3.23.0" description = "Backport of pathlib-compatible object wrapper for zip files" optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" +groups = ["dev"] +markers = "python_version < \"3.12\"" files = [ - {file = "zipp-3.15.0-py3-none-any.whl", hash = "sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556"}, - {file = "zipp-3.15.0.tar.gz", hash = "sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b"}, + {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, + {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, ] [package.extras] -docs = ["furo", "jaraco.packaging (>=9)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] -testing = ["big-O", "flake8 (<5)", "jaraco.functools", "jaraco.itertools", "more-itertools", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=1.3)", "pytest-flake8", "pytest-mypy (>=0.9.1)"] +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"] [metadata] -lock-version = "2.0" -python-versions = ">=3.7" -content-hash = "5345802a891bb155e45e41024f780dd9de461f3a290555b8150104abbd315202" +lock-version = "2.1" +python-versions = ">=3.9" +content-hash = "8d7135c3f6faa54226334f03a9b31f95a06fe047b1651b8340830cb5c0a8e9d1" diff --git a/pyproject.toml b/pyproject.toml index 00d6646..041b13d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -10,11 +10,11 @@ packages = [ ] readme = "README.md" classifiers = [ - "Programming Language :: Python :: 3.7", - "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", ] # including this would turn on pyproject.toml for setuptools and fail validation @@ -26,7 +26,7 @@ classifiers = [ [tool.poetry.dependencies] # core dependencies -python = ">=3.7" +python = ">=3.9" urllib3 = ">=1.25.4" requests = [{version = ">=2.26.0", markers = "python_version<'3.8'"},{version = ">=2.32.0", markers = "python_version>='3.8'"}] werkzeug = [{version = ">2.0.0", markers = "python_version<'3.8'"},{version = ">=3.0.3", markers = "python_version>='3.8'"}] @@ -87,7 +87,7 @@ exclude = [ ] lint.unfixable = ["SIM112"] line-length = 120 -target-version = "py37" +target-version = "py39" [tool.pytest.ini_options] @@ -98,7 +98,7 @@ norecursedirs = ".git .venv .eggs build dist terraform features" [tool.black] line-length = 120 -target-version = ['py37'] +target-version = ['py39'] include = '\.pyi?$' #extend-exclude = ''' #/( @@ -114,15 +114,15 @@ include = '\.pyi?$' [tool.tox] legacy_tox_ini = """ [tox] -envlist = py37,py38,py39,py310,py311 +envlist = py39,py310,py311,py312,py313 [gh-actions] python = - 3.7: py37 - 3.8: py38 3.9: py39 3.10: py310 3.11: py311 + 3.12: py312 + 3.13: py313 [testenv:.pkg] set_env = @@ -183,7 +183,7 @@ show_missing = true output = "reports/coverage.xml" [tool.mypy] -python_version = "3.7" +python_version = "3.9" warn_return_any = true warn_unused_configs = true show_error_codes = true @@ -191,7 +191,7 @@ check_untyped_defs = true [tool.poetry-dynamic-versioning] -enable = true +enable = false metadata = false vcs = "git" style = "pep440" diff --git a/setup.py b/setup.py index a640391..309a942 100755 --- a/setup.py +++ b/setup.py @@ -1,7 +1,7 @@ #!/usr/bin/env python """ - this shim is required ... because the PyPI package name contains upper case chars . and pyproject.toml - will lowercase under PEP-518 build systems. +this shim is required ... because the PyPI package name contains upper case chars . and pyproject.toml +will lowercase under PEP-518 build systems. """ import os from os.path import dirname, join diff --git a/sonar-project.properties b/sonar-project.properties index 3e7b68f..eb408f6 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -2,7 +2,7 @@ sonar.projectVersion=2.0 sonar.projectKey=NHSDigital_mesh-client sonar.organization=nhsdigital sonar.host.url=https://sonarcloud.io -sonar.python.version=3.7 +sonar.python.version=3.9 #sonar.exclusions= sonar.test.inclusions=tests/**/*.py sonar.cpd.exclusions=tests/**/*.py diff --git a/tests/helpers.py b/tests/helpers.py index 3a12df9..0ccf86d 100644 --- a/tests/helpers.py +++ b/tests/helpers.py @@ -1,7 +1,8 @@ import contextlib import json import os -from typing import Mapping, Optional +from collections.abc import Mapping +from typing import Optional from werkzeug import Response @@ -16,8 +17,8 @@ """ Usable default values for verify and cert, providing certificates and keys which should work with mock_server. Note that these certs will not work with -any NHS Digital test environments - such certs must be obtained from -NHS Digital. +any NHS England test environments - such certs must be obtained from +NHS England. """ default_ssl_opts = MOCK_SSL_OPTS diff --git a/tests/mesh_endpoint_connectivity_tests.py b/tests/mesh_endpoint_connectivity_tests.py index 3941ce3..a42d132 100644 --- a/tests/mesh_endpoint_connectivity_tests.py +++ b/tests/mesh_endpoint_connectivity_tests.py @@ -4,6 +4,7 @@ from urllib.parse import urlparse import pytest +from requests.exceptions import ConnectionError as RequestsConnectionError from requests.exceptions import HTTPError, SSLError import mesh_client @@ -27,14 +28,23 @@ def _host_resolves(endpoint: Endpoint): _INTERNET_ENDPOINTS = [(name, endpoint) for name, endpoint in _ENDPOINTS if not name.startswith("DEPRECATED_HSCN_")] _HSCN_ENDPOINTS = [(name, endpoint) for name, endpoint in _ENDPOINTS if name.startswith("DEPRECATED_HSCN_")] +_DEP_HSCN_ENDPOINT = [(name, endpoint) for name, endpoint in _HSCN_ENDPOINTS if name == "DEPRECATED_HSCN_DEP_ENDPOINT"] +_NON_DEP_HSCN_ENDPOINTS = [ + (name, endpoint) for name, endpoint in _HSCN_ENDPOINTS if name != "DEPRECATED_HSCN_DEP_ENDPOINT" +] + +CONNECTION_ABORTED_ERROR = "Connection aborted." +REMOTE_END_CLOSED_CONNECTION = "Remote end closed connection without response" +CANNOT_CONNECT_TO_PROXY = "Cannot connect to proxy." @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints(name: str, endpoint: Endpoint): - with pytest.raises(HTTPError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY) - ) as client: + with ( + pytest.raises(HTTPError) as err, + MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, + ): client.ping() assert err.value.response is not None @@ -44,9 +54,10 @@ def test_hscn_endpoints(name: str, endpoint: Endpoint): @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_verify_false(name: str, endpoint: Endpoint): - with pytest.raises(HTTPError) as err, MeshClient( - endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False - ) as client: + with ( + pytest.raises(HTTPError) as err, + MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False) as client, + ): client.ping() assert err.value.response is not None @@ -57,88 +68,113 @@ def test_hscn_endpoints_verify_false(name: str, endpoint: Endpoint): @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_defaults_from_hostname(name: str, endpoint: Endpoint): - with pytest.raises(HTTPError) as err, MeshClient( - endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY) - ) as client: + with ( + pytest.raises(HTTPError) as err, + MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, + ): client.ping() assert err.value.response is not None assert err.value.response.status_code == 400 + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text -@pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) -@pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") -def test_hscn_endpoints_common_name_check_false(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False - ) as client: +@pytest.mark.parametrize(("name", "endpoint"), _DEP_HSCN_ENDPOINT) +@pytest.mark.skipif( + not _host_resolves(mesh_client.DEPRECATED_HSCN_DEP_ENDPOINT), reason="these hosts will only resolve on HSCN" +) +def test_dep_hscn_endpoint_common_name_check_false(name: str, endpoint: Endpoint): + with ( + pytest.raises(SSLError) as err, + MeshClient( + endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False + ) as client, + ): client.ping() assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" +@pytest.mark.parametrize(("name", "endpoint"), _NON_DEP_HSCN_ENDPOINTS) +@pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") +def test_non_dep_hscn_endpoints_common_name_check_false(name: str, endpoint: Endpoint): + with ( + pytest.raises(HTTPError) as err, + MeshClient( + endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False + ) as client, + ): + client.ping() + + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert err.value.response.status_code == 400 + assert "SSL certificate error" in err.value.response.text + + @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY) - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_common_name_check_false(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient( + endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False + ) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - if endpoint.hostname_checks_common_name: - assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" - else: - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_verify_false(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_defaults_from_hostname(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_with_port_defaults_from_hostname(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - f"{endpoint.url}:443", "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient( + f"{endpoint.url}:443", "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None + ) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize( @@ -147,14 +183,17 @@ def test_internet_endpoints_with_port_defaults_from_hostname(name: str, endpoint ) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_hostname: bool): - with pytest.raises(HTTPError) as err, MeshClient( - endpoint.url, - "BADUSERNAME", - "BADPASSWORD", - cert=(MOCK_CERT, MOCK_KEY), - verify=endpoint.verify, - check_hostname=check_hostname, - ) as client: + with ( + pytest.raises(HTTPError) as err, + MeshClient( + endpoint.url, + "BADUSERNAME", + "BADPASSWORD", + cert=(MOCK_CERT, MOCK_KEY), + verify=endpoint.verify, + check_hostname=check_hostname, + ) as client, + ): client.ping() assert err.value.response is not None @@ -167,31 +206,37 @@ def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_host [(ep[0], ep[1], check_hostname) for check_hostname, ep in itertools.product([True, False], _INTERNET_ENDPOINTS)], ) def test_internet_endpoints_check_hostname(name: str, endpoint: Endpoint, check_hostname: bool): - with pytest.raises(SSLError) as err, MeshClient( - endpoint.url, - "BADUSERNAME", - "BADPASSWORD", - cert=(MOCK_CERT, MOCK_KEY), - verify=endpoint.verify, - check_hostname=check_hostname, - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient( + endpoint.url, + "BADUSERNAME", + "BADPASSWORD", + cert=(MOCK_CERT, MOCK_KEY), + verify=endpoint.verify, + check_hostname=check_hostname, + ) as client, + ): client.ping() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): - with pytest.raises(HTTPError) as err, MeshClient( - endpoint, - "BADUSERNAME", - "BADPASSWORD", - cert=(MOCK_CERT, MOCK_KEY), - proxies={"https": "http://localhost:8019"}, - ) as client: + with ( + pytest.raises(HTTPError) as err, + MeshClient( + endpoint, + "BADUSERNAME", + "BADPASSWORD", + cert=(MOCK_CERT, MOCK_KEY), + proxies={"https": "http://localhost:8019"}, + timeout=10, + ) as client, + ): client.ping() assert err.value.response is not None @@ -201,9 +246,11 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_via_an_ambient_proxy(name: str, endpoint: Endpoint): - with temp_env_vars(HTTPS_PROXY="http://localhost:8019"), pytest.raises(HTTPError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY) - ) as client: + with ( + temp_env_vars(HTTPS_PROXY="http://localhost:8019"), + pytest.raises(HTTPError) as err, + MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, + ): client.ping() assert err.value.response is not None @@ -213,27 +260,30 @@ def test_hscn_endpoints_via_an_ambient_proxy(name: str, endpoint: Endpoint): @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_via_explicit_proxy(name: str, endpoint: Endpoint): - with pytest.raises(SSLError) as err, MeshClient( - endpoint, - "BADUSERNAME", - "BADPASSWORD", - cert=(MOCK_CERT, MOCK_KEY), - proxies={"https": "http://localhost:8019"}, - ) as client: + with ( + pytest.raises(RequestsConnectionError) as err, + MeshClient( + endpoint, + "BADUSERNAME", + "BADPASSWORD", + cert=(MOCK_CERT, MOCK_KEY), + proxies={"https": "http://localhost:8019"}, + ) as client, + ): client.handshake() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CANNOT_CONNECT_TO_PROXY + assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_via_ambient_proxy(name: str, endpoint: Endpoint): - with temp_env_vars(HTTPS_PROXY="http://localhost:8019"), pytest.raises(SSLError) as err, MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY) - ) as client: + with ( + temp_env_vars(HTTPS_PROXY="http://localhost:8019"), + pytest.raises(RequestsConnectionError) as err, + MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, + ): client.handshake() - # the internet endpoints behave differently they will not return a 400 bad request - # in this case, TLSV1_ALERT_UNKNOWN_CA actually means "I don't accept this client certificate" - assert err.value.args[0].reason.args[0].reason == "TLSV1_ALERT_UNKNOWN_CA" + assert err.value.args[0].reason.args[0] == CANNOT_CONNECT_TO_PROXY + assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION From 009fed37ed48129282be5f90e4d210887e91e1e3 Mon Sep 17 00:00:00 2001 From: davidhallam4-nhs <110543996+davidhallam4-nhs@users.noreply.github.com> Date: Wed, 30 Jul 2025 15:00:04 +0100 Subject: [PATCH 2/5] MESH-2092 linting fixes --- mesh_client/__init__.py | 60 +++--- mesh_client/io_helpers.py | 4 +- mesh_client/types.py | 286 ++++++++++++------------- pyproject.toml | 4 +- scripts/sonar_tests.py | 11 +- tests/mesh_noretry_send_chunk_tests.py | 20 +- tests/mesh_retry_send_chunk_tests.py | 20 +- tests/mesh_sandbox_tests.py | 4 +- 8 files changed, 197 insertions(+), 212 deletions(-) diff --git a/mesh_client/__init__.py b/mesh_client/__init__.py index d8693fc..e1128bd 100644 --- a/mesh_client/__init__.py +++ b/mesh_client/__init__.py @@ -16,7 +16,7 @@ from io import BytesIO from itertools import chain from types import TracebackType -from typing import Any, Dict, List, NoReturn, Optional, Tuple, Type, TypeVar, Union, cast +from typing import Any, NoReturn, Optional, TypeVar, Union, cast from urllib.parse import quote as q from urllib.parse import urlparse @@ -46,14 +46,14 @@ TrackingResponse_v2, ) -if sys.version_info[:2] < (3, 8): - warnings.warn("python 3.7 is now end of life", category=DeprecationWarning, stacklevel=2) +if sys.version_info[:2] < (3, 9): # noqa: UP036 + warnings.warn( + "python versions < 3.9 are end of life and no longer supported as of mesh-client v4", + category=DeprecationWarning, + stacklevel=2, + ) -if sys.version_info[:2] >= (3, 8): - # TODO: Import directly (no need for conditional) when `python_requires = >= 3.8` - from importlib.metadata import PackageNotFoundError, version -else: - from importlib_metadata import PackageNotFoundError, version +from importlib.metadata import PackageNotFoundError, version def _get_version(*names: str) -> str: @@ -76,7 +76,7 @@ def _get_version(*names: str) -> str: DEFAULT_MEDIA_TYPE = "application/octet-stream" -_OPTIONAL_HEADERS: Dict[str, str] = { +_OPTIONAL_HEADERS: dict[str, str] = { "workflow_id": "Mex-WorkflowID", "filename": "Mex-FileName", "local_id": "Mex-LocalID", @@ -89,7 +89,7 @@ def _get_version(*names: str) -> str: } -def optional_header_map() -> Dict[str, str]: +def optional_header_map() -> dict[str, str]: return _OPTIONAL_HEADERS.copy() @@ -136,7 +136,7 @@ def optional_header_map() -> Dict[str, str]: # urllib3 'futures' ( not part of 1.26 .. but available in 2.x ) def reraise( - tp: Optional[Type[BaseException]], + tp: Optional[type[BaseException]], value: BaseException, tb: Optional[TracebackType] = None, ) -> NoReturn: @@ -195,7 +195,7 @@ def _looks_like_send_error(status_code: int, response_dict: dict) -> bool: def _get_send_error_message( response_dict: dict, -) -> Tuple[str, Union[SendMessageErrorResponse_v1, SendMessageErrorResponse_v2, dict]]: +) -> tuple[str, Union[SendMessageErrorResponse_v1, SendMessageErrorResponse_v2, dict]]: if "errorDescription" in response_dict: return response_dict["errorDescription"], cast(SendMessageErrorResponse_v1, response_dict) @@ -243,7 +243,7 @@ def increment( class SSLContextAdapter(HTTPAdapter): def __init__( self, - cert: Optional[Union[Tuple[str], Tuple[str, str], Tuple[str, str, str]]] = None, + cert: Optional[Union[tuple[str], tuple[str, str], tuple[str, str, str]]] = None, verify: Optional[Union[str, bool]] = None, check_hostname: Optional[bool] = None, hostname_checks_common_name: Optional[bool] = None, @@ -310,17 +310,17 @@ def __init__( # noqa: C901 mailbox: str, password: str, shared_key: Optional[bytes] = None, - cert: Optional[Union[Tuple[str], Tuple[str, str], Tuple[str, str, str]]] = None, + cert: Optional[Union[tuple[str], tuple[str, str], tuple[str, str, str]]] = None, verify: Optional[Union[str, bool]] = None, check_hostname: Optional[bool] = None, hostname_checks_common_name: Optional[bool] = None, max_chunk_size=75 * 1024 * 1024, - proxies: Optional[Dict[str, str]] = None, + proxies: Optional[dict[str, str]] = None, transparent_compress: bool = False, max_retries: Union[int, Retry] = 3, retry_backoff_factor: Union[int, float] = 0.5, - retry_status_force_list: Tuple[int, ...] = (425, 429, 502, 503, 504), - retry_methods: Tuple[str, ...] = ("HEAD", "GET", "PUT", "POST", "DELETE", "OPTIONS", "TRACE"), + retry_status_force_list: tuple[int, ...] = (425, 429, 502, 503, 504), + retry_methods: tuple[str, ...] = ("HEAD", "GET", "PUT", "POST", "DELETE", "OPTIONS", "TRACE"), timeout: Union[int, float] = 10 * 60, application_name: Optional[str] = None, ): @@ -499,7 +499,7 @@ def lookup_endpoint(self, ods_code: str, workflow_id: str) -> EndpointLookupResp return cast(EndpointLookupResponse_v2, response.json()) def _inbox_v2_page( - self, url: Optional[str] = None, params: Optional[Dict[str, Any]] = None + self, url: Optional[str] = None, params: Optional[dict[str, Any]] = None ) -> ListMessageResponse_v2: url = url or f"{self.mailbox_url}/inbox" response = self._session.get(url, timeout=self._timeout, params=params) @@ -507,7 +507,7 @@ def _inbox_v2_page( return cast(ListMessageResponse_v2, response.json()) - def list_messages(self, max_results: Optional[int] = None, workflow_filter: Optional[str] = None) -> List[str]: + def list_messages(self, max_results: Optional[int] = None, workflow_filter: Optional[str] = None) -> list[str]: """ lists messages ids in the inbox; note if workflow_filter is set it's possible to receive an empty page when more results exist outside the first max_results @@ -518,10 +518,10 @@ def list_messages(self, max_results: Optional[int] = None, workflow_filter: Opti workflow_filter (Optional[str]): workflow filter string Returns: - List[str]: message ids + list[str]: message ids """ - params: Dict[str, Union[str, int]] = {} + params: dict[str, Union[str, int]] = {} if max_results: if max_results < 10: raise ValueError("if set max_results should be >= 10") @@ -532,7 +532,7 @@ def list_messages(self, max_results: Optional[int] = None, workflow_filter: Opti result = self._inbox_v2_page(params=params) - return cast(List[str], result.get("messages", [])) + return cast(list[str], result.get("messages", [])) def retrieve_message(self, message_id: str) -> "Message": """ @@ -572,7 +572,7 @@ def retrieve_message_chunk(self, message_id: str, chunk_num: int) -> Response: @staticmethod def _headers_for_chunk( recipient: str, chunk_num: int, total_chunks: int, compress: bool, **kwargs - ) -> Dict[str, str]: + ) -> dict[str, str]: if chunk_num > 1: headers = { "Content-Type": DEFAULT_MEDIA_TYPE, @@ -793,7 +793,7 @@ def iterate_message_ids( Generator[str]: message ids """ - params: Dict[str, Union[int, str]] = {} + params: dict[str, Union[int, str]] = {} if batch_size: if batch_size < 10: raise ValueError("if set batch_size should be >= 10") @@ -802,9 +802,9 @@ def iterate_message_ids( if workflow_filter: params["workflow_filter"] = workflow_filter - def _next_messages(page_result: ListMessageResponse_v2) -> Tuple[Optional[str], List[str]]: - return cast(Dict[str, str], page_result.get("links", {})).get("next"), cast( - List[str], page_result.get("messages", []) + def _next_messages(page_result: ListMessageResponse_v2) -> tuple[Optional[str], list[str]]: + return cast(dict[str, str], page_result.get("links", {})).get("next"), cast( + list[str], page_result.get("messages", []) ) result = self._inbox_v2_page(params=params) @@ -941,7 +941,7 @@ class _BaseMessage: def __init__(self, msg_id: str, response, client): self._msg_id = msg_id self._client = client - self._mex_headers: Dict[str, Any] = {} + self._mex_headers: dict[str, Any] = {} headers = response.headers @@ -994,7 +994,7 @@ def readline(self) -> bytes: """ return self._stream.readline() - def readlines(self) -> List[bytes]: + def readlines(self) -> list[bytes]: """ Read all lines from the message """ @@ -1014,7 +1014,7 @@ def acknowledge(self): """ self._client.acknowledge_message(self._msg_id) - def mex_header(self, key: str, default: Optional[TDefault] = None) -> Union[str, TDefault]: + def mex_header(self, key: str, default: Optional[TDefault] = None) -> Union[str, Optional[TDefault]]: """get a mex header if present Args: diff --git a/mesh_client/io_helpers.py b/mesh_client/io_helpers.py index f571eb8..c0b6b37 100644 --- a/mesh_client/io_helpers.py +++ b/mesh_client/io_helpers.py @@ -3,7 +3,7 @@ import os import warnings import zlib -from typing import List, cast +from typing import cast class IteratorMixin: @@ -40,7 +40,7 @@ def readline(self) -> bytes: except StopIteration: return b"" - def readlines(self) -> List[bytes]: + def readlines(self) -> list[bytes]: return list(iter(self)) diff --git a/mesh_client/types.py b/mesh_client/types.py index fcd447b..0d02fbc 100644 --- a/mesh_client/types.py +++ b/mesh_client/types.py @@ -1,149 +1,137 @@ -import sys -from typing import Dict, List, Optional, Union - -if sys.version_info[:2] < (3, 9): - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/endpointlookup/-ods_code-/-workflow_id- - EndpointLookupResponse_v1 = Dict[str, Union[str, List[Dict[str, str]]]] - EndpointLookupItem_v2 = Dict[str, str] - EndpointLookupResponse_v2 = Dict[str, List[Dict[str, str]]] - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/inbox - ListMessageResponse_v1 = Dict[str, List[str]] - ListMessageResponse_v2 = Dict[str, Union[List[str], Dict[str, str], int]] - CountMessagesResponse_v1 = Dict[str, Union[str, int, bool]] - CountMessagesResponse_v2 = Dict[str, int] - AcknowledgeMessageResponse_v1 = Dict[str, str] - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking/-local_id- - TrackingResponse_v1 = Dict[str, Union[str, int, bool]] - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking - TrackingResponse_v2 = Dict[str, Union[str, int, bool]] - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#post-/messageexchange/-mailbox_id-/outbox - SendMessageResponse_v1 = Dict[str, str] - SendMessageResponse_v2 = Dict[str, str] - SendMessageErrorResponse_v1 = Dict[str, str] - SendMessageErrorResponse_v2 = Dict[str, Union[str, List[Dict[str, str]]]] - - -else: - from typing import Literal, TypedDict - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/endpointlookup/-ods_code-/-workflow_id- - - class EndpointLookupItem_v1(TypedDict): - address: str - description: Optional[str] - endpoint_type: Literal["MESH"] - - class EndpointLookupResponse_v1(TypedDict): - query_id: str - results: List[EndpointLookupItem_v1] - - class EndpointLookupItem_v2(TypedDict): - mailbox_id: str - mailbox_name: Optional[str] - - class EndpointLookupResponse_v2(TypedDict): - results: List[EndpointLookupItem_v2] - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/inbox - class ListMessageResponse_v1(TypedDict): - messages: List[str] - - class ListMessageResponse_v2(TypedDict): - messages: List[str] - links: Dict[Literal["self", "next"], str] - approx_inbox_count: int - - class CountMessagesResponse_v1(TypedDict): - count: int - internalID: str - allResultsIncluded: bool - - class CountMessagesResponse_v2(TypedDict): - count: int - - class AcknowledgeMessageResponse_v1(TypedDict): - messageId: str - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking/-local_id- - class TrackingResponse_v1(TypedDict): - addressType: Optional[str] - checksum: Optional[str] - chunkCount: Optional[int] - compressFlag: Optional[str] - contentEncoding: Optional[str] - downloadTimestamp: Optional[str] - dtsId: str - encryptedFlag: Optional[str] - expiryTime: Optional[str] - failureDate: Optional[str] - failureDiagnostic: Optional[str] - fileName: Optional[str] - fileSize: int - - isCompressed: Optional[str] - linkedMsgId: Optional[str] - localId: Optional[str] - meshRecipientOdsCode: Optional[str] - messageId: str - messageType: Optional[str] - partnerId: Optional[str] - - recipient: Optional[str] - recipientName: Optional[str] - recipientOrgCode: Optional[str] - recipientOrgName: Optional[str] - recipientSmtp: Optional[str] - - sender: Optional[str] - senderName: Optional[str] - senderOdsCode: Optional[str] - senderOrgCode: Optional[str] - senderOrgName: Optional[str] - senderSmtp: Optional[str] - - status: Optional[str] - - statusCode: Optional[str] - statusDescription: Optional[str] - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking - class TrackingResponse_v2(TypedDict): - message_id: str - local_id: Optional[str] - workflow_id: Optional[str] - filename: Optional[str] - - expiry_time: Optional[str] - upload_timestamp: Optional[str] - - recipient: Optional[str] - recipient_name: Optional[str] - recipient_ods_code: Optional[str] - recipient_org_code: Optional[str] - recipient_org_name: Optional[str] - - status_success: Optional[bool] - status: Optional[str] - status_event: Optional[str] - status_timestamp: Optional[str] - status_description: Optional[str] - status_code: Optional[str] - - # https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#post-/messageexchange/-mailbox_id-/outbox - class SendMessageResponse_v1(TypedDict): - messageID: str - - class SendMessageResponse_v2(TypedDict): - message_id: str - - class SendMessageErrorResponse_v1(TypedDict): - messageID: Optional[str] - errorEvent: Optional[str] - errorCode: Optional[str] - errorDescription: Optional[str] - - class SendMessageErrorResponse_v2(TypedDict): - message_id: Optional[str] - internal_id: Optional[str] - detail: List[dict] +from typing import Literal, Optional, TypedDict + +# https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/endpointlookup/-ods_code-/-workflow_id- + + +class EndpointLookupItem_v1(TypedDict): + address: str + description: Optional[str] + endpoint_type: Literal["MESH"] + + +class EndpointLookupResponse_v1(TypedDict): + query_id: str + results: list[EndpointLookupItem_v1] + + +class EndpointLookupItem_v2(TypedDict): + mailbox_id: str + mailbox_name: Optional[str] + + +class EndpointLookupResponse_v2(TypedDict): + results: list[EndpointLookupItem_v2] + + +# https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/inbox +class ListMessageResponse_v1(TypedDict): + messages: list[str] + + +class ListMessageResponse_v2(TypedDict): + messages: list[str] + links: dict[Literal["self", "next"], str] + approx_inbox_count: int + + +class CountMessagesResponse_v1(TypedDict): + count: int + internalID: str + allResultsIncluded: bool + + +class CountMessagesResponse_v2(TypedDict): + count: int + + +class AcknowledgeMessageResponse_v1(TypedDict): + messageId: str + + +# https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking/-local_id- +class TrackingResponse_v1(TypedDict): + addressType: Optional[str] + checksum: Optional[str] + chunkCount: Optional[int] + compressFlag: Optional[str] + contentEncoding: Optional[str] + downloadTimestamp: Optional[str] + dtsId: str + encryptedFlag: Optional[str] + expiryTime: Optional[str] + failureDate: Optional[str] + failureDiagnostic: Optional[str] + fileName: Optional[str] + fileSize: int + + isCompressed: Optional[str] + linkedMsgId: Optional[str] + localId: Optional[str] + meshRecipientOdsCode: Optional[str] + messageId: str + messageType: Optional[str] + partnerId: Optional[str] + + recipient: Optional[str] + recipientName: Optional[str] + recipientOrgCode: Optional[str] + recipientOrgName: Optional[str] + recipientSmtp: Optional[str] + + sender: Optional[str] + senderName: Optional[str] + senderOdsCode: Optional[str] + senderOrgCode: Optional[str] + senderOrgName: Optional[str] + senderSmtp: Optional[str] + + status: Optional[str] + + statusCode: Optional[str] + statusDescription: Optional[str] + + +# https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#get-/messageexchange/-mailbox_id-/outbox/tracking +class TrackingResponse_v2(TypedDict): + message_id: str + local_id: Optional[str] + workflow_id: Optional[str] + filename: Optional[str] + + expiry_time: Optional[str] + upload_timestamp: Optional[str] + + recipient: Optional[str] + recipient_name: Optional[str] + recipient_ods_code: Optional[str] + recipient_org_code: Optional[str] + recipient_org_name: Optional[str] + + status_success: Optional[bool] + status: Optional[str] + status_event: Optional[str] + status_timestamp: Optional[str] + status_description: Optional[str] + status_code: Optional[str] + + +# https://digital.nhs.uk/developer/api-catalogue/message-exchange-for-social-care-and-health-api#post-/messageexchange/-mailbox_id-/outbox +class SendMessageResponse_v1(TypedDict): + messageID: str + + +class SendMessageResponse_v2(TypedDict): + message_id: str + + +class SendMessageErrorResponse_v1(TypedDict): + messageID: Optional[str] + errorEvent: Optional[str] + errorCode: Optional[str] + errorDescription: Optional[str] + + +class SendMessageErrorResponse_v2(TypedDict): + message_id: Optional[str] + internal_id: Optional[str] + detail: list[dict] diff --git a/pyproject.toml b/pyproject.toml index 041b13d..5ae1d90 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,9 +78,7 @@ lint.select = [ "SIM", # flake8-simplify ] src = ["."] -lint.ignore = [ - "PT004" -] +lint.ignore = [] exclude = [ ".git", ".venv", diff --git a/scripts/sonar_tests.py b/scripts/sonar_tests.py index c73b962..c9e3c7c 100755 --- a/scripts/sonar_tests.py +++ b/scripts/sonar_tests.py @@ -3,10 +3,9 @@ import re import xml.dom.minidom as dom from collections import defaultdict -from typing import Dict, List, Tuple -def _get_test_suites(test_src: str) -> List[dom.Element]: +def _get_test_suites(test_src: str) -> list[dom.Element]: src_tree: dom.Document = dom.parse(test_src) src_root = src_tree.documentElement @@ -46,7 +45,7 @@ def _add_test_detail_if_present(case_src: dom.Element, case_out: dom.Element, do def _translate_test_case( case_src: dom.Element, dom_out: dom.Document, is_feature_file: bool -) -> Tuple[str, dom.Element]: +) -> tuple[str, dom.Element]: classname = case_src.getAttribute("classname") test_name = case_src.getAttribute("name") duration = round(float(case_src.getAttribute("time") or "0") * 1000, 0) @@ -61,7 +60,7 @@ def _translate_test_case( return test_file, case_out -def _get_tests_from_file(test_src: str, dom_out: dom.Document) -> Dict[str, List[dom.Element]]: +def _get_tests_from_file(test_src: str, dom_out: dom.Document) -> dict[str, list[dom.Element]]: is_feature_file = os.path.basename(test_src).startswith("TESTS-") test_suites = _get_test_suites(test_src) @@ -71,7 +70,7 @@ def _get_tests_from_file(test_src: str, dom_out: dom.Document) -> Dict[str, List print(test_src, "suites", len(test_suites), "cases", len(test_cases)) - tests: Dict[str, List[dom.Element]] = defaultdict(list) + tests: dict[str, list[dom.Element]] = defaultdict(list) for test_case in test_cases: test_file, case_out = _translate_test_case(test_case, dom_out, is_feature_file) @@ -102,7 +101,7 @@ def _transform_xunit_results(reports_dir: str, output_sonar: str): dom_out = dom.getDOMImplementation().createDocument(None, "testExecutions", None) dom_out.documentElement.setAttribute("version", "1") - all_tests: Dict[str, List[dom.Element]] = defaultdict(list) + all_tests: dict[str, list[dom.Element]] = defaultdict(list) for source_file in os.listdir(src_junit): if not source_file.endswith(".xml"): diff --git a/tests/mesh_noretry_send_chunk_tests.py b/tests/mesh_noretry_send_chunk_tests.py index 6f874d1..274978f 100644 --- a/tests/mesh_noretry_send_chunk_tests.py +++ b/tests/mesh_noretry_send_chunk_tests.py @@ -1,7 +1,7 @@ import os.path import re from collections import defaultdict -from typing import Dict, List, cast +from typing import cast from uuid import uuid4 import pytest @@ -55,8 +55,8 @@ def test_chunk_retries(httpserver: HTTPServer, alice: MeshClient, bob: MeshClien assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) - received_chunks: List[bytes] = [] + chunk_call_counts: dict[int, int] = defaultdict(int) + received_chunks: list[bytes] = [] def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -66,7 +66,7 @@ def send_chunk_handler(request: Request): if chunk_num == 1: received_chunks.append(request.data) - return json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + return json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) if chunk_num == 2 and chunk_call_counts[chunk_num] < 4: return plain_response("", status=502) @@ -95,8 +95,8 @@ def test_chunk_all_retries_fail(httpserver: HTTPServer, alice: MeshClient, bob: assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) - received_chunks: List[bytes] = [] + chunk_call_counts: dict[int, int] = defaultdict(int) + received_chunks: list[bytes] = [] def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -106,7 +106,7 @@ def send_chunk_handler(request: Request): if chunk_num == 1: received_chunks.append(request.data) - return json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + return json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) return plain_response("", status=502) @@ -133,8 +133,8 @@ def test_chunk_retries_with_file(httpserver: HTTPServer, alice: MeshClient, bob: assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) - received_chunks: List[bytes] = [] + chunk_call_counts: dict[int, int] = defaultdict(int) + received_chunks: list[bytes] = [] def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -144,7 +144,7 @@ def send_chunk_handler(request: Request): if chunk_num == 1: received_chunks.append(request.data) - return json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + return json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) if chunk_num == 2 and chunk_call_counts[chunk_num] < 4: return plain_response("", status=502) diff --git a/tests/mesh_retry_send_chunk_tests.py b/tests/mesh_retry_send_chunk_tests.py index ee5b3bd..f4c0e4f 100644 --- a/tests/mesh_retry_send_chunk_tests.py +++ b/tests/mesh_retry_send_chunk_tests.py @@ -3,7 +3,7 @@ import sys from collections import defaultdict from time import sleep -from typing import Dict, List, cast +from typing import cast from uuid import uuid4 import pytest @@ -106,8 +106,8 @@ def test_chunk_retries(httpserver: HTTPServer, alice: MeshClient, bob: MeshClien assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) - received_chunks: List[bytes] = [] + chunk_call_counts: dict[int, int] = defaultdict(int) + received_chunks: list[bytes] = [] def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -117,7 +117,7 @@ def send_chunk_handler(request: Request): if chunk_num == 1: received_chunks.append(request.data) - return json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + return json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) if chunk_num == 2 and chunk_call_counts[chunk_num] < 4: return plain_response("", status=502) @@ -156,13 +156,13 @@ def test_chunk_all_retries_fail(httpserver: HTTPServer, alice: MeshClient, bob: message_id = uuid4().hex.upper() httpserver.expect_request(f"{alice.mailbox_path}/outbox", method="POST").respond_with_response( - json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) ) send_re = re.compile(rf"^{alice.mailbox_path}/outbox/{message_id}/\d+") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/1") - chunk_call_counts: Dict[int, int] = defaultdict(int) + chunk_call_counts: dict[int, int] = defaultdict(int) chunk_call_counts[1] += 1 @@ -189,7 +189,7 @@ def test_chunk_first_chunk_fails(httpserver: HTTPServer, alice: MeshClient, bob: assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) + chunk_call_counts: dict[int, int] = defaultdict(int) def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -219,8 +219,8 @@ def test_chunk_retries_with_file(httpserver: HTTPServer, alice: MeshClient, bob: assert send_re.match(f"{alice.mailbox_path}/outbox") assert send_re.match(f"{alice.mailbox_path}/outbox/{message_id}/2") - chunk_call_counts: Dict[int, int] = defaultdict(int) - received_chunks: List[bytes] = [] + chunk_call_counts: dict[int, int] = defaultdict(int) + received_chunks: list[bytes] = [] def send_chunk_handler(request: Request): last_path = request.path.split("/")[-1] @@ -230,7 +230,7 @@ def send_chunk_handler(request: Request): if chunk_num == 1: received_chunks.append(request.data) - return json_response(cast(SendMessageResponse_v2, {"message_id": message_id}), status=202) + return json_response(cast(dict, cast(SendMessageResponse_v2, {"message_id": message_id})), status=202) if chunk_num == 2 and chunk_call_counts[chunk_num] < 4: return plain_response("", status=502) diff --git a/tests/mesh_sandbox_tests.py b/tests/mesh_sandbox_tests.py index 39fc70d..4e40d59 100644 --- a/tests/mesh_sandbox_tests.py +++ b/tests/mesh_sandbox_tests.py @@ -1,6 +1,6 @@ import io import os.path -from typing import List, cast +from typing import cast from uuid import uuid4 import pytest @@ -305,7 +305,7 @@ def test_msg_id_tracking(alice: MeshClient, bob: MeshClient): def test_endpoint_lookup(alice: MeshClient, bob: MeshClient): result = alice.lookup_endpoint("X26", "RESTRICTED_WORKFLOW") - result_list = cast(List[dict], result["results"]) + result_list = cast(list[dict], result["results"]) assert len(result_list) == 1 assert result_list[0]["mailbox_id"] == "BOB" assert result_list[0]["mailbox_name"] == "TESTMB2" From 5d0047a77c5880e715020b5d10cd81bc92dc92db Mon Sep 17 00:00:00 2001 From: davidhallam4-nhs <110543996+davidhallam4-nhs@users.noreply.github.com> Date: Fri, 1 Aug 2025 15:49:38 +0100 Subject: [PATCH 3/5] MESH-2092 support up to py3.13 - required changed to SSL certs as 3.13 is more security conscious. Pulled out tox config into tox.ini to permit running from pycharm. Use ASDF python versions. Update Sonar version --- .github/workflows/merge-develop.yml | 2 +- .github/workflows/pull-request.yml | 3 +- .tool-versions | 2 +- Makefile | 6 +- mesh_client/__init__.py | 2 +- pyproject.toml | 32 +--- scripts/create-test-certs-keys.sh | 58 ++++++++ scripts/openssl.cnf | 28 ++++ tests/ca.cert.pem | 31 ---- tests/ca.key.pem | 51 ------- tests/client.cert.pem | 31 ---- tests/client.key.pem | 51 ------- tests/mesh_endpoint_connectivity_tests.py | 174 ++++++++++++---------- tests/mesh_sandbox_tests.py | 2 - tests/server.cert.pem | 33 ---- tests/server.key.pem | 51 ------- tox.ini | 43 ++++++ 17 files changed, 238 insertions(+), 362 deletions(-) create mode 100755 scripts/create-test-certs-keys.sh create mode 100644 scripts/openssl.cnf delete mode 100644 tests/ca.cert.pem delete mode 100644 tests/ca.key.pem delete mode 100644 tests/client.cert.pem delete mode 100644 tests/client.key.pem delete mode 100644 tests/server.cert.pem delete mode 100644 tests/server.key.pem create mode 100644 tox.ini diff --git a/.github/workflows/merge-develop.yml b/.github/workflows/merge-develop.yml index 7b8c8cc..bb1b3d9 100644 --- a/.github/workflows/merge-develop.yml +++ b/.github/workflows/merge-develop.yml @@ -66,7 +66,7 @@ jobs: - name: provision sonar-scanner if: github.actor != 'dependabot[bot]' && (success() || failure()) run: | - export SONAR_VERSION="4.7.0.2747" + export SONAR_VERSION="5.0.1.3006" wget -q "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VERSION}.zip" -O sonar-scanner.zip unzip -q ./sonar-scanner.zip mv ./sonar-scanner-${SONAR_VERSION} ./sonar-scanner diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index d726a20..163ed9f 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -146,7 +146,7 @@ jobs: - name: provision sonar-scanner if: github.actor != 'dependabot[bot]' && (success() || failure()) run: | - export SONAR_VERSION="4.7.0.2747" + export SONAR_VERSION="5.0.1.3006" wget -q "https://binaries.sonarsource.com/Distribution/sonar-scanner-cli/sonar-scanner-cli-${SONAR_VERSION}.zip" -O sonar-scanner.zip unzip -q ./sonar-scanner.zip mv ./sonar-scanner-${SONAR_VERSION} ./sonar-scanner @@ -308,6 +308,7 @@ jobs: - name: add poetry plugins run: | poetry self add "poetry-dynamic-versioning[plugin]" + poetry self add poetry-plugin-export - name: build dist run: | diff --git a/.tool-versions b/.tool-versions index 34b3b60..9c18e83 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1,2 +1,2 @@ poetry 2.1.3 -python 3.10.18 3.9.23 3.11.13 3.12.11 3.13.5 +python 3.13.5 3.12.11 3.11.13 3.10.18 3.9.23 diff --git a/Makefile b/Makefile index c022c72..5034609 100644 --- a/Makefile +++ b/Makefile @@ -93,7 +93,6 @@ black-check: black: poetry run black . - coverage-cleanup: rm -f .coverage* || true @@ -121,7 +120,7 @@ tox: down: docker compose down --remove-orphans || true -up: +up: create-test-certs-keys docker compose up -d --remove-orphans --build coverage-ci: coverage-cleanup coverage-ci-test coverage-report @@ -134,3 +133,6 @@ check-secrets-all: export-requirements: poetry export --only main -f requirements.txt --output ./requirements.txt + +create-test-certs-keys: + ./scripts/create-test-certs-keys.sh diff --git a/mesh_client/__init__.py b/mesh_client/__init__.py index e1128bd..f1fe70e 100644 --- a/mesh_client/__init__.py +++ b/mesh_client/__init__.py @@ -220,7 +220,7 @@ def increment( error: Optional[Exception] = None, _pool: Optional[ConnectionPool] = None, _stacktrace: Optional[TracebackType] = None, - ) -> Retry: + ) -> "MeshRetry": if method != "POST" or not url or not url.endswith("/outbox"): return super().increment(method, url, response, error, _pool, _stacktrace) diff --git a/pyproject.toml b/pyproject.toml index 5ae1d90..3c884e6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -109,36 +109,6 @@ include = '\.pyi?$' -[tool.tox] -legacy_tox_ini = """ -[tox] -envlist = py39,py310,py311,py312,py313 - -[gh-actions] -python = - 3.9: py39 - 3.10: py310 - 3.11: py311 - 3.12: py312 - 3.13: py313 - -[testenv:.pkg] -set_env = - RELEASE_VERSION=1.2.3 - -[testenv] -wheel_build_env = .pkg -use_develop = true -package = wheel -deps = - requests>=2.26.0 - mock - pytest - pytest-httpserver -commands = - python -m pytest - -""" [tool.coverage.run] branch = true @@ -189,7 +159,7 @@ check_untyped_defs = true [tool.poetry-dynamic-versioning] -enable = false +enable = true metadata = false vcs = "git" style = "pep440" diff --git a/scripts/create-test-certs-keys.sh b/scripts/create-test-certs-keys.sh new file mode 100755 index 0000000..6450c9b --- /dev/null +++ b/scripts/create-test-certs-keys.sh @@ -0,0 +1,58 @@ +#!/bin/bash + +set -euo pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )" +OUTPUT_DIR="$SCRIPT_DIR/../tests" + +######################### CA ######################### + +echo "Generating CA private key and certificate..." + +openssl genpkey -algorithm RSA -out "$OUTPUT_DIR"/ca.key.pem + +openssl req -new -x509 -days 73050 -key "$OUTPUT_DIR"/ca.key.pem -out "$OUTPUT_DIR"/ca.cert.pem \ + -config "$SCRIPT_DIR"/openssl.cnf -extensions v3_ca -subj "/CN=Test Self-Signed CA" + +echo "CA certificate and key created successfully." + +######################### SERVER ######################### + +echo "Generating server private key and CSR..." + +openssl genpkey -algorithm RSA -out "$OUTPUT_DIR"/server.key.pem + +openssl req -new -key "$OUTPUT_DIR"/server.key.pem -out "$OUTPUT_DIR"/server.csr \ + -config "$SCRIPT_DIR"/openssl.cnf -subj "/CN=localhost/O=Test Server" + +echo "Signing the server CSR with the CA certificate..." + +openssl x509 -req -in "$OUTPUT_DIR"/server.csr -CA "$OUTPUT_DIR"/ca.cert.pem -CAkey "$OUTPUT_DIR"/ca.key.pem \ + -CAcreateserial -out "$OUTPUT_DIR"/server.cert.pem -days 73050 -extensions v3_req \ + -extfile "$SCRIPT_DIR"/openssl.cnf + +echo "Server certificate signed successfully." + +######################### CLIENT ######################### + +echo "Generating client private key and CSR..." + +openssl genpkey -algorithm RSA -out "$OUTPUT_DIR"/client.key.pem + +openssl req -new -key "$OUTPUT_DIR"/client.key.pem -out "$OUTPUT_DIR"/client.csr \ + -config "$SCRIPT_DIR"/openssl.cnf -subj "/CN=localhost/O=Test Client" + +echo "Signing the client CSR with the CA certificate..." + +openssl x509 -req -in "$OUTPUT_DIR"/client.csr -CA "$OUTPUT_DIR"/ca.cert.pem -CAkey "$OUTPUT_DIR"/ca.key.pem \ + -CAcreateserial -out "$OUTPUT_DIR"/client.cert.pem -days 73050 -extensions v3_req \ + -extfile "$SCRIPT_DIR"/openssl.cnf + +echo "Client certificate signed successfully." + +######################### COMPLETE ######################### + +rm -f "$OUTPUT_DIR"/server.csr "$OUTPUT_DIR"/client.csr + +echo "Complete." + diff --git a/scripts/openssl.cnf b/scripts/openssl.cnf new file mode 100644 index 0000000..a019ce5 --- /dev/null +++ b/scripts/openssl.cnf @@ -0,0 +1,28 @@ +[ req ] +distinguished_name = req_distinguished_name +prompt = no + +[ req_distinguished_name ] +C = GB +ST = Test State +L = Test Locality +O = Test Org +CN = Test Self-Signed CA + +[ v3_ca ] +# Extensions for a self-signed CA +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer +basicConstraints = critical,CA:true +keyUsage = critical,digitalSignature,keyCertSign,cRLSign + +[ v3_req ] +# Extensions for a server/client certificate +basicConstraints = CA:false +keyUsage = digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth, clientAuth +subjectAltName = @alt_names + +[ alt_names ] +DNS.1 = localhost +IP.1 = 127.0.0.1 diff --git a/tests/ca.cert.pem b/tests/ca.cert.pem deleted file mode 100644 index d29bf27..0000000 --- a/tests/ca.cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFXzCCA0egAwIBAgIJALRbCSor9bEbMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV -BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX -aWRnaXRzIFB0eSBMdGQwIBcNMTYwNDIwMTczOTA5WhgPMjIxNjAzMDMxNzM5MDla -MEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJ -bnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDTHtXZykS5dsvFvhMWKB43p79NWJfHgH0sy4fDAQ1fU/lXc7kzR398 -sIWu67l1Tc9YqhTatPNSR+WPlc7O7bEB+1iLcoMzNFHawHLGOPFv+owjJsY3XMLV -rOUPOpzT+ggaieI+FBxx0PIDfleRiTdkAtozC5wKDxEJtrpt4blMMit7VaeTp7dX -ryJv1VAq034wjLzLjBI2l9H7Gx+JVCGtrxTxwDZrpoIdkJ7uCxOdO3bwpT2fvR8O -RwmefC90q25sabeIodJxu2iqqRawHtaQ7g4WEimK1ed4hUoyOkxwtjfYV26vRXUP -vJlTuoh3FhHZw5xAODBt+fMqJFjPlAYfCtMkXVNflu5ObTrQ5iQme40Ugbh3rSNE -fQV68D6Qs9Bfs9EWMBx3h8PsLg7WCbaKhcm0oMavHXr12lH/z/nCf+cU+61U1yJ+ -Bn9g2Fn8iEb7b4J3qpQ+Cxf/pYknrXsgYY4p8j0EkQgBZDoHr7Tgb+koUOcn1InK -NQLX2KV7MTe9P7ikn/kbE+HpW5bCL+N2KETV9qlqJ0mUR2H5+eaX+yme2Af0afFZ -Z9rb97jzC9Elad3F6NK7Jdr6u3cPKIaU3qbuYDq3MxdtMGjiWyYRzixofpMgUqYm -8EEv6GsT+eZNY+rhlyUkEou6upgOkLmZcNsbEM/K+JJm0bW87YoVBwIDAQABo1Aw -TjAdBgNVHQ4EFgQUXxJ+6UmJ4cVNqXurwQJeyQALP4YwHwYDVR0jBBgwFoAUXxJ+ -6UmJ4cVNqXurwQJeyQALP4YwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOC -AgEAmrJdePkitQtZmhopjnw11eT0WmvZnZfPDccm8LJ8uevQfHKdM5uruDGeE0r5 -SbUGuxC08Bs42ZNnqbXsbSzK7piHBfwG95VYC9knfBBg2Gv9EDKSJnr8NXdDyJeF -caycrkFeGkdRal3bCfXO3rHQiMtukFG+x/OzD9gjEPEfmbBXC/gOesWJNFmS4doG -+A4lAIXEbvDYdlzH/jh9C26t8LWwRirL9Hn6fHQbN4ywDH4n3FRvSElwH/uk/mEv -4ksPphrAV760Rxsjy6XM2+IwFs1BrQVkPKT91WirFampmvsKModqhXJPb0SPLdd0 -G4sfyeiRzbzDjiq4igvD1HLIulPrbkdpLNUOsaSL56xE19FpHjl95OI9leKQeUMd -No3A+gh00sBCYZvhHXCPVACQGOke8JeChxBmqWWuOdBXyXyE9iSZtN4SqNhWjGTQ -97cqxZ4zgzmvb5FaGyG6ZmlWjCpkwNpbETp6CmqqN4sr//QnY+fc/6k5E3V31JWu -lB6mv/JlORiEnDZjP6fO1L7yEvvc1vMlMMDCfNLbU5sdmp3LouR1Yf7uMzGzVL8r -MsL1ds0kLcY9oQlduXOumM/bj+0hJTHxc06tr9ilzDAgQ+m48+xLxa6+X27m5pnl -W/JNIRmhLoeFNGNh8HvhI2PwOCsFiqT1rrCaUtusTyH0Ggs= ------END CERTIFICATE----- diff --git a/tests/ca.key.pem b/tests/ca.key.pem deleted file mode 100644 index a4ff18a..0000000 --- a/tests/ca.key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEA0x7V2cpEuXbLxb4TFigeN6e/TViXx4B9LMuHwwENX1P5V3O5 -M0d/fLCFruu5dU3PWKoU2rTzUkflj5XOzu2xAftYi3KDMzRR2sByxjjxb/qMIybG -N1zC1azlDzqc0/oIGoniPhQccdDyA35XkYk3ZALaMwucCg8RCba6beG5TDIre1Wn -k6e3V68ib9VQKtN+MIy8y4wSNpfR+xsfiVQhra8U8cA2a6aCHZCe7gsTnTt28KU9 -n70fDkcJnnwvdKtubGm3iKHScbtoqqkWsB7WkO4OFhIpitXneIVKMjpMcLY32Fdu -r0V1D7yZU7qIdxYR2cOcQDgwbfnzKiRYz5QGHwrTJF1TX5buTm060OYkJnuNFIG4 -d60jRH0FevA+kLPQX7PRFjAcd4fD7C4O1gm2ioXJtKDGrx169dpR/8/5wn/nFPut -VNcifgZ/YNhZ/IhG+2+Cd6qUPgsX/6WJJ617IGGOKfI9BJEIAWQ6B6+04G/pKFDn -J9SJyjUC19ilezE3vT+4pJ/5GxPh6VuWwi/jdihE1fapaidJlEdh+fnml/spntgH -9GnxWWfa2/e48wvRJWndxejSuyXa+rt3DyiGlN6m7mA6tzMXbTBo4lsmEc4saH6T -IFKmJvBBL+hrE/nmTWPq4ZclJBKLurqYDpC5mXDbGxDPyviSZtG1vO2KFQcCAwEA -AQKCAgEAqDsXD6BFWUCXqjAHR42aXqEWKM0izT/O/2YD/dkVzdO9iflWJ82egj6r -mDKQqy/gvPdy/MBacEOIYv1uOahgd4LREPWkJKZZX6YhD2GKyr9s8gnQw4bwXpKS -SKtdEvFXicY7+VnPPMbSQwRnRTqBX/mB5FEo+z78RbBNKIhJPrVvvq0HhvqLd5zA -JTtm0WmMUaWkP9KTJNuf4KfBXo4i9CLi3q1a8DdT0blPW8KJ063x3lreGy7500e6 -G4c7zY1ZxZwMOx0v857yDaQFxzwboIuBwAajAdXnyDr2X8Xi6aHaKFOriJEhcfPI -flbSrYpxmQRtuyLLPKeDJB6ogmii4qCVcnotw9co1yz3nRXbPOaTw+pDg7ZZveDn -02Ip+ayQFrQVzS9aZmZr4eR+Hh6681Ujng3Zrdp03rUXpQ1opyjN1K4rExIRjEiK -Q9cP/0Y3LF5mpwfm0+SxdbZ6FAa57N5quSobNaWGTb1SYF1BtPf/B6s2RfUZOjhg -pwKBF4fL/eHnCfqV8dWlOBs48TwdYrLxurOEGkqFicGdKGO8ayERHpmFD+V7YNbd -PrwyoUbK9Jh8ApslRLTOBcDz+3Cx1oogDMHXkMy7FzvG6s54RgA0SS+SzsS5yMDP -XF7iymVzdwDTeaA0y2lPgHD/nnVfwzZttXiRvLILOKTemp+NrPECggEBAPU6oyJO -+zYeBoDs8aT0YU0OfyfUJa3ZKvIp0AZ8nKU/6otlPu/2gtoHrJfPo0XssczEs3py -wMSX+WxNASKCVRtbqRWVJa/8tRf3YfDeUUrS1aWyD1UEQG6RwG+ACB4W0l+RRVhS -YBgDyjivPy0OK2hm6T8ctoMWlVv76uhwWkfkFsIzLfQ8HEeySjMngxPW69lgw9/v -Sl6fiMeWdsDtoHGqHqluMBLxvBuaLdaFpiNSP+npPweRkii01DWlMojpPWYDVpo5 -fx62qBUhk+SineYmzKfmUT972T4EHvK0WGSm3BKQB1K0H9wMlBJXXVaQMl0fQ/bw -6AAwOugU/fqycX8CggEBANxkrhOMrc5x2Juvn6rzpdG1w29qKUWInpS8tvKdJ4fd -5iT+A4y4a6rHLGxFQRWePNJ+6uqmy/zwr74BLineDc9slc51PRz/T9S6odAHDWIP -X4qho8xfzzN8gSnjrc3TGlpnQAA5u8I/nggfzCUDBYNBmYai7mbuD2ckpRGKf2dr -dNA77azK5n7HBJqS4dkCphnoSwZicmtsT94Ol6AbmIDkyyLfJ0uBuSPtjZj0rySu -li/0oR6tilVgphvPKeuxcaD4YmA7S6MpIv8Kvl/8960Wh1qEDTDrAr7t7TU6mz9z -5vc2rFix19WFDyeCfse6Igfcgg3Pge9l/yWHoVglkHkCggEAFtkBvf6R1Tby8Cwj -T3UdY6qIGlPfttTW9X0DzrbpeVP9LEOgm4biJiI06GgGFEu7PRLOjggHAcoPCRIb -mvV9rHDbzhD5U+49iSAZVfHArTH7idaPKyKcRjD6Nuk82GDT9Od6CIKURWiE/McH -IdGCJdYAwUqRjqEaBVnxRvrAzpXnsOxHycuX7u4jj6SMx9psWvJzDXgj+7Dtc3sH -UW5SVoS9GpgTjpBLMF8rCiOlmQDex5JdtvzPG0/NvbnIfY0NlWWWOgRFXb0y59Ub -DGBCSeEvjC0fQMTvNqH3qDE5UxdgxbH5nLD/jub1HMha/+eraZWyJV3In8vekSTz -jNn3TQKCAQByWtcsE6GXbeD7nxvU4wlWD97xL39ssd++w1CWAE8jo1KoPRjwajyL -Zz84ipKjufBLNEmGKbfMbcJyb0BZvvshdnEgqBpmsl7kvVX6j7409E8ZqpdIEyp6 -x45pgtaK5o9U+x/tPgebWdEQ3Bbb2X6BxYb4og/bXoildxEjUd6bddkttvqy3rDM -dU2BOtdu933iEXLkRC6kaJXkXWP1UnxF3PE+DdXgytWau8bt53/9I42QInl7ZoZR -mI13/nz865xO7rJ0xi+P4GdlOFjhi2uj5v2iTMRfboGFOgULynYFbYkZGshAWT7p -bloXoRFRZtYDiDn/Gn2MDztdaMuh5hPZAoIBAQDEASV+dXBNZOIxQ5IQVn6xMOTs -kKiA539B0lD2CDJQI7UXeat1sJXHZx8QVodY1VwQCJW8u4XLxphgC1Wx9+EjXek8 -+C8OxuXZamXgRaGeCFn3Ev3XsQnRiDVJJZ34JuDBP+hcGIj4JPHQE9qEsPKRBkyJ -yIBNWf7N1eRRn5h4cVMolnvbulEppXYTlKDKqYgrNecIESiWd8WHPeudkWLmDcfy -+yLvICQmVjHWsNWD3uuT3gEGdeKDIzEnovXUmqhQE7N/YDupTv5hkh8hMKl12XGs -3WJ4bVSmp3MOQ2EF4zrAl4fXEd4lS3JxKtzbHFbSogAmPFnuP8wIDWTDgfEq ------END RSA PRIVATE KEY----- diff --git a/tests/client.cert.pem b/tests/client.cert.pem deleted file mode 100644 index c3a4ed9..0000000 --- a/tests/client.cert.pem +++ /dev/null @@ -1,31 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFPTCCAyUCCQDtCP4zrHuZGDANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJB -VTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0 -cyBQdHkgTHRkMCAXDTE2MTAyNjE2MDIxNVoYDzIyMTYwOTA4MTYwMjE1WjB6MQsw -CQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJu -ZXQgV2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QxHzAdBgkqhkiG -9w0BCQEWEHRlc3RAZXhhbXBsZS5jb20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAw -ggIKAoICAQDZTjEmgmx2iqHo82sgpMhdfeDzUah1DRbuc3Zmn5aV25rtaVvOrt/j -OK1ctdX2RcivjcxgpBYg9JH74g+UhiJyIlOAOKWG7DGUnRRysX1WYrH4JqkBbZNk -5FVTegSh32dG0KS54WQEiSTumxiR4kNwE1FUrAPzaOQQaNuuNwspJw99YvjSLwlp -plhm/D1VA1DKRCQPjwEJ7pX1FzrvwSdnSD5YzJOY4vXX8r2ttQz1dLAOSjNtg95R -l0c9GPPLtocMdtdjCEuktvreFjKwfRJTIM1/NvRsFu3UXqjWq4WdRjoxsSoM6fbQ -JQ44nhd+eUxpBVlhclmduxNdlz0+zaXulwoVbpE/nWyLzrBUL76lqY+OYOOm6Lkv -/5GFZ5XzHlxafTQ2Is3CYEB6Dtu9Upu7iQ0rrzIJ77hhnmTT0r6QuIGCnew0PSWz -MGajS03c9FsNpNV1lpuDyH+sqdNiDrRvFt6an1MT+mNHzASl9Q7fetsxYme+ezpw -PN1Fx/S5sB44P1jEadGxV2Jp6oLKCiGuPH318Lw6GHBo7ZiFz9jruDWvdKxoS7QW -hyC5TBzKQDiT1LcmaaWgx72Nr7tnLbHt7Rx0KqmLxe8vEn11NhYhs6F7brGbgeIM -jWuq9K76mU4BhU3t0GBhDYMs6ImpWewQ+VNHrMb3KXDFhAeOza1QcwIDAQABMA0G -CSqGSIb3DQEBCwUAA4ICAQBuYkJe9IMEAHOxwIQucQSE3S8WC7FPc3ypex795nr3 -/5gRN+dWTKJZ65Ah2w18j3uwUgpi6/9vYoEmGzGfbgH3N5qfbabO4Wy+8DtLwCXO -Udf+NLe7MzhZx/wLuOljQyp/ZTym5FoStIoy2Bzkz7AFSrxwiJnL4rx9in5Q55cW -GC4P3Maxk2v6bK8Y8lQlUv2JRfO2xwp89DTy5Z9odRlDRVd2zn0O8papYJ6Q/vL3 -QOOQxmAcbd0CrAVfEp2DMIJMrWOa4vOoHZVKpTFpNmQhYebP5SHxDa47C3EzRxaU -bmATXBIT39rS98305M3dufUsqyB3k/zD630CCvonXbt+OVDzAxA1Zc+uB4qmFVvt -RushDrUnkivAoV7pvIepYkF0XuBCgsT1k3TpXjwIouOlpvT5IQ0EMGapnedNRvrl -Hk9fvfBTkUiUAzTf3XCwkswB1Cv1ba+WLyaeDkjQ1IMXeUt9EZfnuIRXaR2AwSfK -EZ0ozEeL1x9zkbssXA+4uFlhkHaMH0JqTy2zWBl3frIqREqgYODmj6Dh7qnieoYn -9k2yU/Xs3pz/kazjA97NKNxOIZNSyTCGleGfqX7dXtGjcT6mzZvAfiUL6covogyh -9oqSIpHL3MiBT63gzXbQRKO9DfZySCItXSAzRnV7qdcZ1NTY+6a+vSs1ExF5oupJ -9w== ------END CERTIFICATE----- diff --git a/tests/client.key.pem b/tests/client.key.pem deleted file mode 100644 index 433c0bb..0000000 --- a/tests/client.key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKAIBAAKCAgEA2U4xJoJsdoqh6PNrIKTIXX3g81GodQ0W7nN2Zp+Wldua7Wlb -zq7f4zitXLXV9kXIr43MYKQWIPSR++IPlIYiciJTgDilhuwxlJ0UcrF9VmKx+Cap -AW2TZORVU3oEod9nRtCkueFkBIkk7psYkeJDcBNRVKwD82jkEGjbrjcLKScPfWL4 -0i8JaaZYZvw9VQNQykQkD48BCe6V9Rc678EnZ0g+WMyTmOL11/K9rbUM9XSwDkoz -bYPeUZdHPRjzy7aHDHbXYwhLpLb63hYysH0SUyDNfzb0bBbt1F6o1quFnUY6MbEq -DOn20CUOOJ4XfnlMaQVZYXJZnbsTXZc9Ps2l7pcKFW6RP51si86wVC++pamPjmDj -pui5L/+RhWeV8x5cWn00NiLNwmBAeg7bvVKbu4kNK68yCe+4YZ5k09K+kLiBgp3s -ND0lszBmo0tN3PRbDaTVdZabg8h/rKnTYg60bxbemp9TE/pjR8wEpfUO33rbMWJn -vns6cDzdRcf0ubAeOD9YxGnRsVdiaeqCygohrjx99fC8OhhwaO2Yhc/Y67g1r3Ss -aEu0FocguUwcykA4k9S3JmmloMe9ja+7Zy2x7e0cdCqpi8XvLxJ9dTYWIbOhe26x -m4HiDI1rqvSu+plOAYVN7dBgYQ2DLOiJqVnsEPlTR6zG9ylwxYQHjs2tUHMCAwEA -AQKCAgAoiC0iwbD5a2JH0R9qN1IoHhKXT+Pb8VUVpPOwsJOl4BBFuCEnq/aWqzuq -zz/Zb6q/E/PLEtAN1ZBlKwU87sf+AekRQX+eau/UiHgH7JM0SbRoVM2xNn8Hko9X -wqqahtD8pG4VPbUqI2qAFu2+SDXL8c55vJwACtB/Pw+6rwml42NAP/WpPpzC2AQl -MWc/NB8dmxgezs2izJ2r2WlkzuJKoW7/oSjmm26/mMdIXzzLi7hK8gwloTMWhOEE -xGK03JbT/FawYhu53WdthTZvNOT2HGg4EkgE4UH7GqzjXZrOewrfuevd/MXMjRzZ -8qLvNDDMZfMF+g49HWe/TTZfQHxybDLPgAD9a+S1CtnHzTsJZgbWeWWAMIPzUO3s -1lzr46f4JwmVsdL1iD7u4Tx0uD49M1jzsGqv0sfG+I6dicjdSOaG8FAfN7duvWxW -83zwNYXeChqs1DS9rO4hkWiIIF1HLzMHZjRWlDjoy/9TcRNuNHBK1r8p5cybU5qP -059Z+izuUhtxWVN2IXLKvf2CBLjmYxTOlnkGKr4F1/9WvSFqOtnkKrSDGlr6gXXk -b//01sTpHtUU1BKWGMNPUvwd3Dj8nbAjmXpBLKUc5ReqlKi/qTs9uzeHD97w4NeC -zS6TNYTYRxtC4DGQfUPWobSw3wqvjW91XWAmodFfENmAw+cGAQKCAQEA8xJ5He/X -+pF/vC+ha0M7gFJZd9cp/8HlafmUjN9J1FLx9V8pXJqs+cMwnY3iZloxCwUF+uHX -qswEjMHtkXxKzZRybfmiJIKjmlXCUTBpzNp6kTdm2auHbJlvvdeXSVs/EafHTLwg -84/3ndLomyMzYGur++JZg8Jlq5OQqkHnR+PRLWd9kW8+cQu+3GTIjYGUxzC8i++e -johfeHkc8HinVIX1hzdohuyEoJN4XgjZtmIHcyEr2WGBSDXZyTX9e5DpUs4sJuGX -zDhNy6S6QidS0Q3PKsvDnQBMY1IqE+7XI1KbRbybzoFR9nUDvQGQmFemcoxkI3zZ -4rPZstlQOAUYDQKCAQEA5Nzk99MM5SgYeryfL6XUsZxxODYsB7TdlOW5z8lg5nAH -trTzZ4ay/NidNWw4+0XIcthrNFjnQ8JGRsv8h33E4B+p2Fgb/AQZM6foWjN80e4S -Em3/A0VkMsXETZ1vcXcvwlHUIm13idoTw3geLjdqQ1jAOhTLZZLS8Kl31ayBdCVz -Jy7b2vbmZibU7G/DySE1BNDgBtFeebwhHzvq9PxCdQYydab4wXgN9Egam456HWdN -+mtY3S3Lfahe/mg+S8lgnAyUNhZ5MTSrc1EHw0bX5AYfu2klejN+fl0c7R6fWqwI -LRBw7gI6Vvb1c6vlaTZJ2pE3tRG8u4NE5sgC/rVqfwKCAQBpwLLDLJNZ562cUVi4 -UxLzHGDie9FA/bnzJmvT8l2rq76rU5CqQn1ZWOuw0IccosbNlYzpfxKWs5aTKthS -QLJGyPwUDtTVb6UAQ6l8K0UMpE1JGsJ7l14fCI6OGNswRiulYcqa/wqTDSLdHmKn -BGSY4Z98whjR82TKhjQdbvjR1TMvvuPpv216P3L1bj+3GRaCpxiRBVqFhp2Ky56k -nMmoQ3P0NU4bzZFST3bB6rXV3MaC936dYAegRBWRrhSviveIWDzrWaDyb9ig7fU/ -TN6CJ7DnXKmph/S0DY5TB8nAC3OUnp9m8+qWAIj01VZ0gUXgdmYm7m3ZbQgdAOEe -zlCNAoIBAEhmCJjNTvr/IB9TpBfyocI99yMNIAigEqiTs6Aj2F+NeSM3QvixB9Ys -wC6yOaRjgvGxvNgmd6JbxteGmDBUfP9ZhOVHmjKzKTXKHBrMxuOyKE1kNpPWU8gr -/9l9wE9ooNccA7uQXYxiTHY9fW6pYRhE7ypwgZd0Rv6S3bHejGUto6v1it9N07zk -896HzKvHsXoAiZ4ehYCFHwU+cylk07EpcLT/SRoK3H82gBRNkhvTHjvl0YrGfeUW -alaYq3xWDBXRdOFXYqdKPiKQs5/2vT0JIuiqboyl1ZIr6oaodUi9uyhmVxMz6Tix -jxw0eLI71kkqPzEsl0PKVvWauDfTNAkCggEBAMxbT0dlIwl2VW2UVL8yEJsgynKh -o+x5xVeXKqiHI26RFiHbaIz01kAyZjsolVy9n999KJkcDrJhW4f4zxdSkv94kbIi -Xnsw2Qf2/JGHTLTlPeeG4vcDKf8gMfPMH5ERVtWk7k3yH7mJ0Z4p3pntGf0RIvlH -wFjY95YUzPJLxoyWmlZa44CNWYRh5+xYqpBS/Lc8DErtLyjx8IaA97qZE/EJSkzg -dkxuk1AXWRYUh+M++3NTnA+GCH5qvbxHqax6eSrfE3DrOjzyu4L2V+FCE/16Lru3 -jG0CkZG7VX2uN+OUV+PdUtR9ol/+3sQU1Fb06EOFMFD11VEwkEhdu6rth1M= ------END RSA PRIVATE KEY----- diff --git a/tests/mesh_endpoint_connectivity_tests.py b/tests/mesh_endpoint_connectivity_tests.py index a42d132..189b13e 100644 --- a/tests/mesh_endpoint_connectivity_tests.py +++ b/tests/mesh_endpoint_connectivity_tests.py @@ -1,6 +1,7 @@ import itertools import socket from _socket import gaierror +from ssl import SSLCertVerificationError from urllib.parse import urlparse import pytest @@ -28,153 +29,154 @@ def _host_resolves(endpoint: Endpoint): _INTERNET_ENDPOINTS = [(name, endpoint) for name, endpoint in _ENDPOINTS if not name.startswith("DEPRECATED_HSCN_")] _HSCN_ENDPOINTS = [(name, endpoint) for name, endpoint in _ENDPOINTS if name.startswith("DEPRECATED_HSCN_")] -_DEP_HSCN_ENDPOINT = [(name, endpoint) for name, endpoint in _HSCN_ENDPOINTS if name == "DEPRECATED_HSCN_DEP_ENDPOINT"] -_NON_DEP_HSCN_ENDPOINTS = [ - (name, endpoint) for name, endpoint in _HSCN_ENDPOINTS if name != "DEPRECATED_HSCN_DEP_ENDPOINT" -] CONNECTION_ABORTED_ERROR = "Connection aborted." REMOTE_END_CLOSED_CONNECTION = "Remote end closed connection without response" -CANNOT_CONNECT_TO_PROXY = "Cannot connect to proxy." +UNABLE_TO_CONNECT_TO_PROXY = "Unable to connect to proxy" @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints(name: str, endpoint: Endpoint): with ( - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): client.ping() - assert err.value.response is not None - assert err.value.response.status_code == 400 + if err.type == SSLError: + assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" + else: + assert err.value.response is not None + assert err.value.response.status_code == 400 @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_verify_false(name: str, endpoint: Endpoint): with ( - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False) as client, ): client.ping() - assert err.value.response is not None - - assert err.value.response.status_code == 400 + if err.type == SSLError: + assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" + else: + assert err.value.response is not None + assert err.value.response.status_code == 400 @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_defaults_from_hostname(name: str, endpoint: Endpoint): with ( - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): client.ping() - assert err.value.response is not None - - assert err.value.response.status_code == 400 - assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + if err.type == SSLError: + assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" + else: + assert err.value.response is not None + assert err.value.response.status_code == 400 + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text -@pytest.mark.parametrize(("name", "endpoint"), _DEP_HSCN_ENDPOINT) -@pytest.mark.skipif( - not _host_resolves(mesh_client.DEPRECATED_HSCN_DEP_ENDPOINT), reason="these hosts will only resolve on HSCN" -) -def test_dep_hscn_endpoint_common_name_check_false(name: str, endpoint: Endpoint): - with ( - pytest.raises(SSLError) as err, - MeshClient( - endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False - ) as client, - ): - client.ping() - - assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" - - -@pytest.mark.parametrize(("name", "endpoint"), _NON_DEP_HSCN_ENDPOINTS) +@pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") -def test_non_dep_hscn_endpoints_common_name_check_false(name: str, endpoint: Endpoint): +def test_dep_hscn_endpoint_common_name_check_false(name: str, endpoint: Endpoint): with ( - pytest.raises(HTTPError) as err, + pytest.raises((SSLError, HTTPError)) as err, MeshClient( endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False ) as client, ): client.ping() - assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert err.value.response.status_code == 400 - assert "SSL certificate error" in err.value.response.text + if err.type == SSLError: + assert err.value.args[0].reason.args[0].reason == "CERTIFICATE_VERIFY_FAILED" + else: + assert err.value.response is not None + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text + assert err.value.response.status_code == 400 @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_common_name_check_false(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient( endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), hostname_checks_common_name=False ) as client, ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_verify_false(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=False) as client, ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_defaults_from_hostname(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient(endpoint.url, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None) as client, ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_with_port_defaults_from_hostname(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient( f"{endpoint.url}:443", "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), verify=None ) as client, ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize( @@ -184,7 +186,7 @@ def test_internet_endpoints_with_port_defaults_from_hostname(name: str, endpoint @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_hostname: bool): with ( - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient( endpoint.url, "BADUSERNAME", @@ -196,9 +198,13 @@ def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_host ): client.ping() - assert err.value.response is not None - - assert err.value.response.status_code == 400 + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.response is not None + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text + assert err.value.response.status_code == 400 @pytest.mark.parametrize( @@ -207,7 +213,7 @@ def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_host ) def test_internet_endpoints_check_hostname(name: str, endpoint: Endpoint, check_hostname: bool): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient( endpoint.url, "BADUSERNAME", @@ -219,15 +225,18 @@ def test_internet_endpoints_check_hostname(name: str, endpoint: Endpoint, check_ ): client.ping() - assert err.value.args[0].reason.args[0] == CONNECTION_ABORTED_ERROR - assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.response is None + assert isinstance(err.value.args[0].reason.args[1], ConnectionResetError) @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): with ( - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient( endpoint, "BADUSERNAME", @@ -238,9 +247,14 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): ) as client, ): client.ping() - assert err.value.response is not None - assert err.value.response.status_code == 400 + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.response is not None + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text + assert err.value.response.status_code == 400 @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @@ -248,20 +262,24 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): def test_hscn_endpoints_via_an_ambient_proxy(name: str, endpoint: Endpoint): with ( temp_env_vars(HTTPS_PROXY="http://localhost:8019"), - pytest.raises(HTTPError) as err, + pytest.raises((HTTPError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): client.ping() - assert err.value.response is not None - - assert err.value.response.status_code == 400 + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.response is not None + assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" + assert "SSL certificate error" in err.value.response.text + assert err.value.response.status_code == 400 @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_via_explicit_proxy(name: str, endpoint: Endpoint): with ( - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient( endpoint, "BADUSERNAME", @@ -272,18 +290,24 @@ def test_internet_endpoints_via_explicit_proxy(name: str, endpoint: Endpoint): ): client.handshake() - assert err.value.args[0].reason.args[0] == CANNOT_CONNECT_TO_PROXY - assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.args[0].reason.args[0] == UNABLE_TO_CONNECT_TO_PROXY + assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_via_ambient_proxy(name: str, endpoint: Endpoint): with ( temp_env_vars(HTTPS_PROXY="http://localhost:8019"), - pytest.raises(RequestsConnectionError) as err, + pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): client.handshake() - assert err.value.args[0].reason.args[0] == CANNOT_CONNECT_TO_PROXY - assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION + if err.type == SSLError: + assert isinstance(err.value.args[0].reason.args[0], SSLCertVerificationError) + else: + assert err.value.args[0].reason.args[0] == UNABLE_TO_CONNECT_TO_PROXY + assert str(err.value.args[0].reason.args[1]) == REMOTE_END_CLOSED_CONNECTION diff --git a/tests/mesh_sandbox_tests.py b/tests/mesh_sandbox_tests.py index 4e40d59..6972431 100644 --- a/tests/mesh_sandbox_tests.py +++ b/tests/mesh_sandbox_tests.py @@ -196,10 +196,8 @@ def test_readlines(alice: MeshClient, bob: MeshClient): def test_transparent_compression(alice: MeshClient, bob: MeshClient): - print("Sending") message_id = alice.send_message(bob_mailbox, b"Hello Bob Compressed", workflow_id=uuid4().hex, compress=True) assert bob.list_messages() == [message_id] - print("Receiving") msg = bob.retrieve_message(message_id) assert msg.compressed assert msg.read() == b"Hello Bob Compressed" diff --git a/tests/server.cert.pem b/tests/server.cert.pem deleted file mode 100644 index 291e4a1..0000000 --- a/tests/server.cert.pem +++ /dev/null @@ -1,33 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIFvzCCA6egAwIBAgIBATANBgkqhkiG9w0BAQsFADBFMQswCQYDVQQGEwJBVTET -MBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQgV2lkZ2l0cyBQ -dHkgTHRkMCAXDTE2MTExMTEzMzcxMloYDzIyMTYwOTI0MTMzNzEyWjBZMQswCQYD -VQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50ZXJuZXQg -V2lkZ2l0cyBQdHkgTHRkMRIwEAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3 -DQEBAQUAA4ICDwAwggIKAoICAQCsMgqVhiXeXsnwns1x99K7ipDdDnRw72ThUG7J -7XwsSwehStzaTpJTKBDh8XprJHBXKEuCMW338BMkXvILi8ATMHz/zIza9BVSSKo7 -AsOOTTsvcyfJDEIUm9c+39za83HyyA6cNh2kTPz01Rrdzc6qBYDBB4x4iWg9F9Ji -+nM4sFV0jLC//S5KDe4koWTQMt7pbBfJ2Rz6cns20I1SeeM7n9QtjaElTnKi76Ec -E4+HTPvvuVtLyIzJDch1eN8SOvmQE859O0AxbKT3yU9BxuxBsdOhgxEy/aBN2j9B -U1rrfsm+td2ZuWGp2kraFHjdlHEXki2La2Lld5UDvd0qzaE1s4aIi22dKrD1vpaH -ldzhqDcyQOAIyM+lavUPd5LEcL9rMvXhzYdOK0MaL9HJTglog8OP+BXV4e2ewGm/ -PYuBAZX04wWNm9kEMEf2uhUtUQrkp/1+g5hR4oAiCCSSTirAfvOeTwYKbes5ODZ7 -glz9Jv3ZpOg6nDdViHH/OU+2NmlvwhdktXskoZVRSWCcx6Io3Wh8n/KG1pzLzX5g -eIBNJuK3AEkBQFBBvKwDeDXsBtIHzuCxtdeIh+xJ4+NhsFcZwAvebaFMJhBcyruc -uV9aHO2zInI8WslGdplir4mjRzOqHSzlKFBSt95Ycctrh0sDg9HE8bdhCxT0CQ6h -O6eChwIDAQABo4GjMIGgMAkGA1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5T -U0wgR2VuZXJhdGVkIENlcnRpZmljYXRlMB0GA1UdDgQWBBQbSx/0Wexk78z2YUUK -kKhMJh9GCDAfBgNVHSMEGDAWgBRfEn7pSYnhxU2pe6vBAl7JAAs/hjAlBgNVHREE -HjAcggRtZXNoggltZXNoLXRlc3SCCWxvY2FsaG9zdDANBgkqhkiG9w0BAQsFAAOC -AgEAyRrP9E5Vi66skE5vXeO59NLsggjbGB0ccJKGaerlKwk40ps7x9jlPXBjh03a -LyMEM7crvsf9RLDqu+5HEHIVo6GbIWd4o/MRV2lEfZg9vLHvQKAqFGffX2BC0IXP -j+QnGCS62xbpIHKKPLsJR5nJDKYrxOqHtyEsdcDuMZewQeate4tmUM79Tkp2zmKg -iGI8S1AhSiNXHthm91BH/Zqgw4Kyzh6z/oW/YBEr92ZjJPGvf+aokoMf3JfjSDzG -68YpPJVKoTtaqeIaW0Ev3fD6/m5dtjmuNk22t+vViPQh68imt0La3qlf0ZR9Thr4 -v2YF32HkYLnt76ibLqGTYnFa7N6ScKQP+fFFeYqDzczzS8ZXuXCaOfogqCl3Kxs3 -vccRbwdT8dvmVazP0cQezW7Sl2lMR3DV2MGnoGxzTGTz++ehJzccrD3AhLpUtFAO -VblXm58uO23ZVjoNy8smsqNzIwgV6tsUnQ4LmCeUHqC+u9XNEF2MXarOXIq5kbbV -CJBOt4XSrcfd3sgcbQJFkE6LHioDIJ3HF0zl+iRZE1AQuE4mVkIt8eo1LxwqKuLB -FcXSk5oAODtRd8AApmYlNZeAUy5RUNT8CpZs4DG+AUkrot5WciwxPhVGDC/950tO -cv2ji9hYLvt5xlAx5fV4Vr2VXMNTGWU2B3Y+w+0LQye8zt8= ------END CERTIFICATE----- diff --git a/tests/server.key.pem b/tests/server.key.pem deleted file mode 100644 index 2a945b8..0000000 --- a/tests/server.key.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJJwIBAAKCAgEArDIKlYYl3l7J8J7NcffSu4qQ3Q50cO9k4VBuye18LEsHoUrc -2k6SUygQ4fF6ayRwVyhLgjFt9/ATJF7yC4vAEzB8/8yM2vQVUkiqOwLDjk07L3Mn -yQxCFJvXPt/c2vNx8sgOnDYdpEz89NUa3c3OqgWAwQeMeIloPRfSYvpzOLBVdIyw -v/0uSg3uJKFk0DLe6WwXydkc+nJ7NtCNUnnjO5/ULY2hJU5you+hHBOPh0z777lb -S8iMyQ3IdXjfEjr5kBPOfTtAMWyk98lPQcbsQbHToYMRMv2gTdo/QVNa637JvrXd -mblhqdpK2hR43ZRxF5Iti2ti5XeVA73dKs2hNbOGiIttnSqw9b6Wh5Xc4ag3MkDg -CMjPpWr1D3eSxHC/azL14c2HTitDGi/RyU4JaIPDj/gV1eHtnsBpvz2LgQGV9OMF -jZvZBDBH9roVLVEK5Kf9foOYUeKAIggkkk4qwH7znk8GCm3rOTg2e4Jc/Sb92aTo -Opw3VYhx/zlPtjZpb8IXZLV7JKGVUUlgnMeiKN1ofJ/yhtacy81+YHiATSbitwBJ -AUBQQbysA3g17AbSB87gsbXXiIfsSePjYbBXGcAL3m2hTCYQXMq7nLlfWhztsyJy -PFrJRnaZYq+Jo0czqh0s5ShQUrfeWHHLa4dLA4PRxPG3YQsU9AkOoTungocCAwEA -AQKCAgBcVYEDaKmJsf5K/nxfrmnbkpPXVVbu8A+CGiUuNiAtiBYRURlYHmWsHYHg -BiKErUdoFP1YVLUJDDzXdeoIcumN4KRGbiLhjZyZQMm3VuYRuiwQZ4lf7yjH8EDd -QCEnbv8dFlVvQj1myrmhd1wur5sv5D+EQk36nIO+rrVryaxbK4LHOmHUsShPIWUf -U0PBuGV7eTDQVZGKYjTb0bzWCvHkGPIncxiD7qrd3+zeJ0cBYDB//T6NRn7nmHJz -O1syZVlI/rXsxQbI+d8D13ieZtJs77PxmVxxoTqCRJNCrjXErXn0v4SSV6uc7qbQ -hcXB20VBRGsTpYOkVBkdpoOf3h+g0LwAZ+PYGDSwTTVTJL77MuuK6CrYK0yiyzFV -8yxdkFTiA+cRqhz1wE/2EiL1oxOZ2nyDGhOIZOE0LauxR5kbJFbhT4sRdgtWqSLJ -ZiXAuSRSh0vxnod+Dvn/WpnDmarpiE6Eb7BVb9IXyNv1Wymc4g4m0l5cELERDmI4 -WAHPu//tjsD6MIP2GAygK7nJBcb82Su5atzG0/WWUwBsZpFFAzUuXewvt8jTv0dc -FlDItziVMnke3+0hpsaPRyBc8+Fgw/jqjm165wQ49zXk+NTGO2IcGbEawpn/tHq+ -Tjc9VT9yxyh/yiy2BCcElVrVBJeNDTlnU2z/BkcTc0vUO1ZkAQKCAQEA25p9BuqZ -IV4C0bLGOiqn47LYsjGFuSW/dU6Mdyl73TJys0rmP3KBXxfxrsXmTFiEjXwkcGI9 -ofR+jkWJbHf5jZbsWDok4hzsyc6xskVp5KT8vTteEW51gVClry92F+J8AB/v/xKR -NUNPAYP7TmwAx5GcepjtuQ3HEsFdUNhdiBfxT0i7cRBt9eO9/BL8nTGxji9c7e1N -E3lchPb6CwHT+SmEpqJrx3IRdxQIqTRcird5mIAAFeNmhsP1rthr/sE1CUPnP4Rq -G8XiZQv0g9F4zCZthytTtXXc3+51HdgnhQWPICbmy7YLZ/uuy4WXUthLDviNeTE5 -6qBttaGGKRmrhwKCAQEAyLwWrboaXvybSnFh6cMY9TtbrAp8jC7YDAc3KfJNzT4T -FQ4lQj4etlw19y7EhutwOLpGK3Fubrq/Bpgh64RdPB9HM8wsh+40iScucOhDSwbB -U0azwRt5/RfHYDgvwPrWMhqOUPcfTCc9g9C3XokPwKbf5wE76AF2kd9hbAb9FYfm -R7E9FABd2uwvzfdppmkphZ8P4hzfxqHO4kKqbkTES5bjgb3phgjlIukIxL4rUdfE -HJod6XiZ+FslllNiSu07jX5bVdupDi/2OikxteJF9dGa/CtxKe55FkOF15YYnBq6 -VISux0bPCOyyGNnsvnmdTtGi9U8ioU6Hj8N6Gb8xAQKCAQAUDgK2+/uqCWzWe64Q -p86XQ8D4XP9qTiEy9E5tn3M5Wx8QcpmeV7Wq2oPuwxHqDPdl+F1XihE41hwsn/sR -1c8LeCnzULQHlj6lm2Os9RvbjpmqKl7H1r+SZKwM2Je/TKaoWEJRl/98zr3LVKNB -oSldEFYq+AZVrQVuGAyOkoPQJueZpvm/NJHmL7ss5wr8zAn8AyVIcTBlw+KIHgnt -sWgLTBhaI2EWYLtplYHI+ggtft3y6FWZqh+11PV91zPdmwVd6D6ZFV2fVa38LmBR -HXMbqbK88l79plradGtro07QnhZZCFRxbBmUkG6BFZ0hKrGIF3jMBYvVensqaCrZ -XAfHAoIBAGvYca7Aj658tMnYBKzcvqnyTBwwPh3qhPRhZAfLQHWGZiYnxWjDiyia -ffvhSoDaOR6hJVXtyVEAT+UxEvg/0v+cJlrz1PDqz5roTBEpGA5VAMTG9YhIRM/v -WJSfWzipCy88CT4CpvP5GRmapwnJRYdRoHWxuge50YQpqWOqlYpdyyC1XoVCdSpL -Ppu/0yku0roRbS0kKi3DfS0eeAZqN7QMywpHiBEU8lZBMQ7SxN9htuFPA8cNnltK -TPVosyRiNF6ehl+odjlDF1zECQsZGFErXcMha9kFYFTPzja3U117FqSV7Hjv2AeJ -c13ap1DmcdeI1a5J5+cWE8rvUMhIagECggEAP6akk8uRVqz3ur2rNPOLatEizf9d -NYlOW1+gcXvZkytxBS2bKB+83dWqmgnXwmAEkjgedjRtV/DUXPvUALxj5kTa5YeK -vYQ9WNvK+pGCah3B/SnreYb41fpbd2kxoevcFXRxZW1t97xvhE31jJDX1PpX2wTm -HBdj/KghjHHFPCYaqOvqDE5dQbILXSWUiouv/jw0RHR+/3sYdun9kloPHh0eD6dX -1Mjg8JFelwDsbIU13XLD7m7rTnokhngWXcrSOquDBca0cPHV/dbbg1OrxoPazTTk -8CUFSxoETnPfUv3UyeNI5ScHcClB3R9++ylMesSQ7Ve/n8+uaAaXx/GRZA== ------END RSA PRIVATE KEY----- diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..c9c6068 --- /dev/null +++ b/tox.ini @@ -0,0 +1,43 @@ +[tox] +envlist = py{39,310,311,312,313} +isolated_build = True + +[gh-actions] +python = + 3.9: py39 + 3.10: py310 + 3.11: py311 + 3.12: py312 + 3.13: py313 + +[testenv:.pkg] +set_env = + RELEASE_VERSION=1.2.3 + +[testenv] +wheel_build_env = .pkg +use_develop = true +package = wheel +deps = + requests>=2.26.0 + mock + pytest + pytest-httpserver +commands = + pytest + +; Uncomment the following lines to specify base Python versions for each environment when using asdf +;[testenv:py39] +;basepython = {env:HOME}/.asdf/installs/python/3.9.23/bin/python +; +;[testenv:py310] +;basepython = {env:HOME}/.asdf/installs/python/3.10.18/bin/python +; +;[testenv:py311] +;basepython = {env:HOME}/.asdf/installs/python/3.11.13/bin/python +; +;[testenv:py312] +;basepython = {env:HOME}/.asdf/installs/python/3.12.11/bin/python +; +;[testenv:py313] +;basepython = {env:HOME}/.asdf/installs/python/3.13.5/bin/python \ No newline at end of file From 06785d7bedf9a4a6b2b41f98d2892cffb235e5df Mon Sep 17 00:00:00 2001 From: davidhallam4-nhs <110543996+davidhallam4-nhs@users.noreply.github.com> Date: Sat, 2 Aug 2025 04:24:53 +0100 Subject: [PATCH 4/5] MESH-2092 dependency updates --- .github/workflows/merge-develop.yml | 2 +- .github/workflows/pull-request.yml | 2 +- .../scheduled-combine-dependabot-prs.yaml | 2 +- Makefile | 6 +- docker-compose.yml | 1 - mesh_client/__init__.py | 4 +- poetry.lock | 144 ++++++++---------- pyproject.toml | 18 +-- tests/mesh_endpoint_connectivity_tests.py | 20 +-- tox.ini | 2 +- 10 files changed, 96 insertions(+), 105 deletions(-) diff --git a/.github/workflows/merge-develop.yml b/.github/workflows/merge-develop.yml index bb1b3d9..0ae7767 100644 --- a/.github/workflows/merge-develop.yml +++ b/.github/workflows/merge-develop.yml @@ -83,7 +83,7 @@ jobs: - name: publish junit reports if: success() || failure() - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 with: check_name: junit reports report_paths: reports/junit/*.xml diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 163ed9f..5e0c5a0 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -176,7 +176,7 @@ jobs: - name: publish junit reports if: success() || failure() - uses: mikepenz/action-junit-report@v4 + uses: mikepenz/action-junit-report@v5 with: check_name: junit reports report_paths: reports/junit/*.xml diff --git a/.github/workflows/scheduled-combine-dependabot-prs.yaml b/.github/workflows/scheduled-combine-dependabot-prs.yaml index faf91d9..c0612c3 100644 --- a/.github/workflows/scheduled-combine-dependabot-prs.yaml +++ b/.github/workflows/scheduled-combine-dependabot-prs.yaml @@ -25,7 +25,7 @@ jobs: steps: - name: combine-prs id: combine-prs - uses: github/combine-prs@v5.0.0 + uses: github/combine-prs@v5 with: ci_required: ${{ inputs.ci_required == 'YES' }} labels: dependencies diff --git a/Makefile b/Makefile index 5034609..c3fc3b8 100644 --- a/Makefile +++ b/Makefile @@ -75,14 +75,18 @@ ruff-ci: lint: ruff mypy shellcheck -clean: +clean: down rm -rf ./dist || true + rm -rf ./tox || true + rm -rf ./Mesh_Client.egg-info || true + rm -rf ./.venv || true rm -rf ./reports || true rm -f .docker.env || true find . -type d -name '.mypy_cache' | xargs rm -rf || true find . -type d -name '.pytest_cache' | xargs rm -rf || true find . -type d -name '__pycache__' | xargs rm -rf || true find . -type f -name '.coverage' | xargs rm -rf || true + find tests -type f -name '*.pem' | xargs rm -rf || true purge: clean rm -rf .venv || true diff --git a/docker-compose.yml b/docker-compose.yml index 5a3c5af..3db2def 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.9' services: diff --git a/mesh_client/__init__.py b/mesh_client/__init__.py index f1fe70e..1112389 100644 --- a/mesh_client/__init__.py +++ b/mesh_client/__init__.py @@ -222,7 +222,7 @@ def increment( _stacktrace: Optional[TracebackType] = None, ) -> "MeshRetry": if method != "POST" or not url or not url.endswith("/outbox"): - return super().increment(method, url, response, error, _pool, _stacktrace) + return cast(MeshRetry, super().increment(method, url, response, error, _pool, _stacktrace)) if error: raise reraise(type(error), error, _stacktrace) @@ -724,7 +724,7 @@ def send_message( compressed, checksum, partner_id, content_type Returns: - Response: raw http response + message_id: string """ compress = self._transparent_compress if compress is None else compress diff --git a/poetry.lock b/poetry.lock index 7daaec8..7e1bf09 100644 --- a/poetry.lock +++ b/poetry.lock @@ -7,7 +7,6 @@ description = "Annotate AST trees with source code positions" optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "asttokens-3.0.0-py3-none-any.whl", hash = "sha256:e3078351a059199dd5138cb1c706e6430c05eff2ff136af5eb4790f9d28932e2"}, {file = "asttokens-3.0.0.tar.gz", hash = "sha256:0dcd8baa8d62b0c1d118b399b2ddba3c4aff271d0d7a9e0d4c1681c79035bbc7"}, @@ -66,18 +65,18 @@ uvloop = ["uvloop (>=0.15.2)"] [[package]] name = "boto3" -version = "1.39.16" +version = "1.40.1" description = "The AWS SDK for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "boto3-1.39.16-py3-none-any.whl", hash = "sha256:cf843228928fd1caebb46c21fbd757a390ce22672b937a354ae89a1d16cb99f8"}, - {file = "boto3-1.39.16.tar.gz", hash = "sha256:d4ce6ba5c030d7ff2033b35e5574d2414e42b80b937bf40d080e11c4d9d0acc1"}, + {file = "boto3-1.40.1-py3-none-any.whl", hash = "sha256:7c007d5c8ee549e9fcad0927536502da199b27891006ef515330f429aca9671f"}, + {file = "boto3-1.40.1.tar.gz", hash = "sha256:985ed4bf64729807f870eadbc46ad98baf93096917f7194ec39d743ff75b3f1d"}, ] [package.dependencies] -botocore = ">=1.39.16,<1.40.0" +botocore = ">=1.40.1,<1.41.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.13.0,<0.14.0" @@ -86,14 +85,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.39.16" +version = "1.40.1" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "botocore-1.39.16-py3-none-any.whl", hash = "sha256:1f1c3b614ac88fd68f824c481cfd7686460c38fe13c01e2963556e7186be3248"}, - {file = "botocore-1.39.16.tar.gz", hash = "sha256:b5a1416849637aa8e72292ee3e7b11cd0c22f9b96f6043d2ac6ba0092a193188"}, + {file = "botocore-1.40.1-py3-none-any.whl", hash = "sha256:e039774b55fbd6fe59f0f4fea51d156a2433bd4d8faa64fc1b87aee9a03f415d"}, + {file = "botocore-1.40.1.tar.gz", hash = "sha256:bdf30e2c0e8cdb939d81fc243182a6d1dd39c416694b406c5f2ea079b1c2f3f5"}, ] [package.dependencies] @@ -109,14 +108,14 @@ crt = ["awscrt (==0.23.8)"] [[package]] name = "build" -version = "1.2.2.post1" +version = "1.3.0" description = "A simple, correct Python build frontend" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "build-1.2.2.post1-py3-none-any.whl", hash = "sha256:1d61c0887fa860c01971625baae8bdd338e517b836a2f70dd1f7aa3a6b2fc5b5"}, - {file = "build-1.2.2.post1.tar.gz", hash = "sha256:b36993e92ca9375a219c99e606a122ff365a760a2d4bba0caa09bd5278b608b7"}, + {file = "build-1.3.0-py3-none-any.whl", hash = "sha256:7145f0b5061ba90a1500d60bd1b13ca0a8a4cebdd0cc16ed8adf1c0e739f43b4"}, + {file = "build-1.3.0.tar.gz", hash = "sha256:698edd0ea270bde950f53aed21f3a0135672206f3911e0176261a31e0e07b397"}, ] [package.dependencies] @@ -127,11 +126,8 @@ pyproject_hooks = "*" tomli = {version = ">=1.1.0", markers = "python_version < \"3.11\""} [package.extras] -docs = ["furo (>=2023.08.17)", "sphinx (>=7.0,<8.0)", "sphinx-argparse-cli (>=1.5)", "sphinx-autodoc-typehints (>=1.10)", "sphinx-issues (>=3.0.0)"] -test = ["build[uv,virtualenv]", "filelock (>=3)", "pytest (>=6.2.4)", "pytest-cov (>=2.12)", "pytest-mock (>=2)", "pytest-rerunfailures (>=9.1)", "pytest-xdist (>=1.34)", "setuptools (>=42.0.0) ; python_version < \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.10\"", "setuptools (>=56.0.0) ; python_version == \"3.11\"", "setuptools (>=67.8.0) ; python_version >= \"3.12\"", "wheel (>=0.36.0)"] -typing = ["build[uv]", "importlib-metadata (>=5.1)", "mypy (>=1.9.0,<1.10.0)", "tomli", "typing-extensions (>=3.7.4.3)"] uv = ["uv (>=0.1.18)"] -virtualenv = ["virtualenv (>=20.0.35)"] +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 = "cachetools" @@ -289,15 +285,15 @@ colorama = {version = "*", markers = "platform_system == \"Windows\""} [[package]] name = "click" -version = "8.2.1" +version = "8.2.2" description = "Composable command line interface toolkit" optional = false python-versions = ">=3.10" groups = ["dev"] markers = "python_version >= \"3.10\"" files = [ - {file = "click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b"}, - {file = "click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202"}, + {file = "click-8.2.2-py3-none-any.whl", hash = "sha256:52e1e9f5d3db8c85aa76968c7c67ed41ddbacb167f43201511c8fd61eb5ba2ca"}, + {file = "click-8.2.2.tar.gz", hash = "sha256:068616e6ef9705a07b6db727cb9c248f4eb9dae437a30239f56fa94b18b852ef"}, ] [package.dependencies] @@ -314,7 +310,7 @@ files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {local = "python_version < \"4.0\" and sys_platform == \"win32\""} +markers = {local = "sys_platform == \"win32\""} [[package]] name = "coverage" @@ -424,7 +420,6 @@ description = "Decorators for Humans" optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "decorator-5.2.1-py3-none-any.whl", hash = "sha256:d316bb415a2d9e2d2b3abcc4084c6502fc09240e292cd76a76afc106a1c8e04a"}, {file = "decorator-5.2.1.tar.gz", hash = "sha256:65f266143752f734b0a7cc83c46f4618af75b8c5911b00ccb61d0ac9b6da0360"}, @@ -468,7 +463,6 @@ description = "Get the currently executing AST node of a frame, and other inform optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "executing-2.2.0-py2.py3-none-any.whl", hash = "sha256:11387150cad388d62750327a53d3339fad4888b39a6fe233c3afbb54ecffd3aa"}, {file = "executing-2.2.0.tar.gz", hash = "sha256:5d108c028108fe2551d1a7b2e8b713341e2cb4fc0aa7dcf966fa4327a5226755"}, @@ -592,7 +586,7 @@ description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" groups = ["local"] -markers = "python_version >= \"3.10\" and python_version < \"4.0\"" +markers = "python_version >= \"3.10\"" files = [ {file = "ipython-8.37.0-py3-none-any.whl", hash = "sha256:ed87326596b878932dbcb171e3e698845434d8c61b8d8cd474bf663041a9dcf2"}, {file = "ipython-8.37.0.tar.gz", hash = "sha256:ca815841e1a41a1e6b73a0b08f3038af9b2252564d01fc405356d34033012216"}, @@ -632,7 +626,6 @@ description = "An autocompletion tool for Python that can be used for text edito optional = false python-versions = ">=3.6" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "jedi-0.19.2-py2.py3-none-any.whl", hash = "sha256:a8ef22bde8490f57fe5c7681a3c83cb58874daf72b4784de3cce5b6ef6edb5b9"}, {file = "jedi-0.19.2.tar.gz", hash = "sha256:4770dc3de41bde3966b02eb84fbcf557fb33cce26ad23da12c742fb50ecb11f0"}, @@ -736,7 +729,6 @@ description = "Inline Matplotlib backend for Jupyter" optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "matplotlib_inline-0.1.7-py3-none-any.whl", hash = "sha256:df192d39a4ff8f21b1895d72e6a13f5fcc5099f00fa84384e0ea28c2cc0653ca"}, {file = "matplotlib_inline-0.1.7.tar.gz", hash = "sha256:8423b23ec666be3d16e16b60bdd8ac4e86e840ebd1dd11a30b9f117f2fa0ab90"}, @@ -764,44 +756,50 @@ test = ["pytest", "pytest-cov"] [[package]] name = "mypy" -version = "1.17.0" +version = "1.17.1" description = "Optional static typing for Python" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy-1.17.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:f8e08de6138043108b3b18f09d3f817a4783912e48828ab397ecf183135d84d6"}, - {file = "mypy-1.17.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ce4a17920ec144647d448fc43725b5873548b1aae6c603225626747ededf582d"}, - {file = "mypy-1.17.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6ff25d151cc057fdddb1cb1881ef36e9c41fa2a5e78d8dd71bee6e4dcd2bc05b"}, - {file = "mypy-1.17.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:93468cf29aa9a132bceb103bd8475f78cacde2b1b9a94fd978d50d4bdf616c9a"}, - {file = "mypy-1.17.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:98189382b310f16343151f65dd7e6867386d3e35f7878c45cfa11383d175d91f"}, - {file = "mypy-1.17.0-cp310-cp310-win_amd64.whl", hash = "sha256:c004135a300ab06a045c1c0d8e3f10215e71d7b4f5bb9a42ab80236364429937"}, - {file = "mypy-1.17.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9d4fe5c72fd262d9c2c91c1117d16aac555e05f5beb2bae6a755274c6eec42be"}, - {file = "mypy-1.17.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d96b196e5c16f41b4f7736840e8455958e832871990c7ba26bf58175e357ed61"}, - {file = "mypy-1.17.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:73a0ff2dd10337ceb521c080d4147755ee302dcde6e1a913babd59473904615f"}, - {file = "mypy-1.17.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:24cfcc1179c4447854e9e406d3af0f77736d631ec87d31c6281ecd5025df625d"}, - {file = "mypy-1.17.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3c56f180ff6430e6373db7a1d569317675b0a451caf5fef6ce4ab365f5f2f6c3"}, - {file = "mypy-1.17.0-cp311-cp311-win_amd64.whl", hash = "sha256:eafaf8b9252734400f9b77df98b4eee3d2eecab16104680d51341c75702cad70"}, - {file = "mypy-1.17.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f986f1cab8dbec39ba6e0eaa42d4d3ac6686516a5d3dccd64be095db05ebc6bb"}, - {file = "mypy-1.17.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:51e455a54d199dd6e931cd7ea987d061c2afbaf0960f7f66deef47c90d1b304d"}, - {file = "mypy-1.17.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3204d773bab5ff4ebbd1f8efa11b498027cd57017c003ae970f310e5b96be8d8"}, - {file = "mypy-1.17.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:1051df7ec0886fa246a530ae917c473491e9a0ba6938cfd0ec2abc1076495c3e"}, - {file = "mypy-1.17.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f773c6d14dcc108a5b141b4456b0871df638eb411a89cd1c0c001fc4a9d08fc8"}, - {file = "mypy-1.17.0-cp312-cp312-win_amd64.whl", hash = "sha256:1619a485fd0e9c959b943c7b519ed26b712de3002d7de43154a489a2d0fd817d"}, - {file = "mypy-1.17.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c41aa59211e49d717d92b3bb1238c06d387c9325d3122085113c79118bebb06"}, - {file = "mypy-1.17.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0e69db1fb65b3114f98c753e3930a00514f5b68794ba80590eb02090d54a5d4a"}, - {file = "mypy-1.17.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:03ba330b76710f83d6ac500053f7727270b6b8553b0423348ffb3af6f2f7b889"}, - {file = "mypy-1.17.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:037bc0f0b124ce46bfde955c647f3e395c6174476a968c0f22c95a8d2f589bba"}, - {file = "mypy-1.17.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:c38876106cb6132259683632b287238858bd58de267d80defb6f418e9ee50658"}, - {file = "mypy-1.17.0-cp313-cp313-win_amd64.whl", hash = "sha256:d30ba01c0f151998f367506fab31c2ac4527e6a7b2690107c7a7f9e3cb419a9c"}, - {file = "mypy-1.17.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:63e751f1b5ab51d6f3d219fe3a2fe4523eaa387d854ad06906c63883fde5b1ab"}, - {file = "mypy-1.17.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f7fb09d05e0f1c329a36dcd30e27564a3555717cde87301fae4fb542402ddfad"}, - {file = "mypy-1.17.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b72c34ce05ac3a1361ae2ebb50757fb6e3624032d91488d93544e9f82db0ed6c"}, - {file = "mypy-1.17.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434ad499ad8dde8b2f6391ddfa982f41cb07ccda8e3c67781b1bfd4e5f9450a8"}, - {file = "mypy-1.17.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:f105f61a5eff52e137fd73bee32958b2add9d9f0a856f17314018646af838e97"}, - {file = "mypy-1.17.0-cp39-cp39-win_amd64.whl", hash = "sha256:ba06254a5a22729853209550d80f94e28690d5530c661f9416a68ac097b13fc4"}, - {file = "mypy-1.17.0-py3-none-any.whl", hash = "sha256:15d9d0018237ab058e5de3d8fce61b6fa72cc59cc78fd91f1b474bce12abf496"}, - {file = "mypy-1.17.0.tar.gz", hash = "sha256:e5d7ccc08ba089c06e2f5629c660388ef1fee708444f1dee0b9203fa031dee03"}, + {file = "mypy-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3fbe6d5555bf608c47203baa3e72dbc6ec9965b3d7c318aa9a4ca76f465bd972"}, + {file = "mypy-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:80ef5c058b7bce08c83cac668158cb7edea692e458d21098c7d3bce35a5d43e7"}, + {file = "mypy-1.17.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c4a580f8a70c69e4a75587bd925d298434057fe2a428faaf927ffe6e4b9a98df"}, + {file = "mypy-1.17.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:dd86bb649299f09d987a2eebb4d52d10603224500792e1bee18303bbcc1ce390"}, + {file = "mypy-1.17.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:a76906f26bd8d51ea9504966a9c25419f2e668f012e0bdf3da4ea1526c534d94"}, + {file = "mypy-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:e79311f2d904ccb59787477b7bd5d26f3347789c06fcd7656fa500875290264b"}, + {file = "mypy-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ad37544be07c5d7fba814eb370e006df58fed8ad1ef33ed1649cb1889ba6ff58"}, + {file = "mypy-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:064e2ff508e5464b4bd807a7c1625bc5047c5022b85c70f030680e18f37273a5"}, + {file = "mypy-1.17.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:70401bbabd2fa1aa7c43bb358f54037baf0586f41e83b0ae67dd0534fc64edfd"}, + {file = "mypy-1.17.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e92bdc656b7757c438660f775f872a669b8ff374edc4d18277d86b63edba6b8b"}, + {file = "mypy-1.17.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:c1fdf4abb29ed1cb091cf432979e162c208a5ac676ce35010373ff29247bcad5"}, + {file = "mypy-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:ff2933428516ab63f961644bc49bc4cbe42bbffb2cd3b71cc7277c07d16b1a8b"}, + {file = "mypy-1.17.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:69e83ea6553a3ba79c08c6e15dbd9bfa912ec1e493bf75489ef93beb65209aeb"}, + {file = "mypy-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1b16708a66d38abb1e6b5702f5c2c87e133289da36f6a1d15f6a5221085c6403"}, + {file = "mypy-1.17.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:89e972c0035e9e05823907ad5398c5a73b9f47a002b22359b177d40bdaee7056"}, + {file = "mypy-1.17.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:03b6d0ed2b188e35ee6d5c36b5580cffd6da23319991c49ab5556c023ccf1341"}, + {file = "mypy-1.17.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c837b896b37cd103570d776bda106eabb8737aa6dd4f248451aecf53030cdbeb"}, + {file = "mypy-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:665afab0963a4b39dff7c1fa563cc8b11ecff7910206db4b2e64dd1ba25aed19"}, + {file = "mypy-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:93378d3203a5c0800c6b6d850ad2f19f7a3cdf1a3701d3416dbf128805c6a6a7"}, + {file = "mypy-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:15d54056f7fe7a826d897789f53dd6377ec2ea8ba6f776dc83c2902b899fee81"}, + {file = "mypy-1.17.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:209a58fed9987eccc20f2ca94afe7257a8f46eb5df1fb69958650973230f91e6"}, + {file = "mypy-1.17.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:099b9a5da47de9e2cb5165e581f158e854d9e19d2e96b6698c0d64de911dd849"}, + {file = "mypy-1.17.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:fa6ffadfbe6994d724c5a1bb6123a7d27dd68fc9c059561cd33b664a79578e14"}, + {file = "mypy-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:9a2b7d9180aed171f033c9f2fc6c204c1245cf60b0cb61cf2e7acc24eea78e0a"}, + {file = "mypy-1.17.1-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:15a83369400454c41ed3a118e0cc58bd8123921a602f385cb6d6ea5df050c733"}, + {file = "mypy-1.17.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:55b918670f692fc9fba55c3298d8a3beae295c5cded0a55dccdc5bbead814acd"}, + {file = "mypy-1.17.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:62761474061feef6f720149d7ba876122007ddc64adff5ba6f374fda35a018a0"}, + {file = "mypy-1.17.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c49562d3d908fd49ed0938e5423daed8d407774a479b595b143a3d7f87cdae6a"}, + {file = "mypy-1.17.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:397fba5d7616a5bc60b45c7ed204717eaddc38f826e3645402c426057ead9a91"}, + {file = "mypy-1.17.1-cp314-cp314-win_amd64.whl", hash = "sha256:9d6b20b97d373f41617bd0708fd46aa656059af57f2ef72aa8c7d6a2b73b74ed"}, + {file = "mypy-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5d1092694f166a7e56c805caaf794e0585cabdbf1df36911c414e4e9abb62ae9"}, + {file = "mypy-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:79d44f9bfb004941ebb0abe8eff6504223a9c1ac51ef967d1263c6572bbebc99"}, + {file = "mypy-1.17.1-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b01586eed696ec905e61bd2568f48740f7ac4a45b3a468e6423a03d3788a51a8"}, + {file = "mypy-1.17.1-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:43808d9476c36b927fbcd0b0255ce75efe1b68a080154a38ae68a7e62de8f0f8"}, + {file = "mypy-1.17.1-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:feb8cc32d319edd5859da2cc084493b3e2ce5e49a946377663cc90f6c15fb259"}, + {file = "mypy-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d7598cf74c3e16539d4e2f0b8d8c318e00041553d83d4861f87c7a72e95ac24d"}, + {file = "mypy-1.17.1-py3-none-any.whl", hash = "sha256:a9f52c0351c21fe24c21d8c0eb1f62967b262d6729393397b6f443c3b773c3b9"}, + {file = "mypy-1.17.1.tar.gz", hash = "sha256:25e01ec741ab5bb3eec8ba9cdb0f769230368a22c959c4937360efb89b7e9f01"}, ] [package.dependencies] @@ -848,7 +846,6 @@ description = "A Python Parser" optional = false python-versions = ">=3.6" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "parso-0.8.4-py2.py3-none-any.whl", hash = "sha256:a418670a20291dacd2dddc80c377c5c3791378ee1e8d12bffc35420643d43f18"}, {file = "parso-0.8.4.tar.gz", hash = "sha256:eb3a7b58240fb99099a345571deecc0f9540ea5f4dd2fe14c2a99d6b281ab92d"}, @@ -877,7 +874,7 @@ description = "Pexpect allows easy control of interactive console applications." optional = false python-versions = "*" groups = ["local"] -markers = "python_version == \"3.9\" and sys_platform != \"win32\" or python_version < \"4.0\" and sys_platform != \"win32\" and sys_platform != \"emscripten\"" +markers = "python_version == \"3.9\" and sys_platform != \"win32\" or sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "pexpect-4.9.0-py2.py3-none-any.whl", hash = "sha256:7236d1e080e4936be2dc3e326cec0af72acf9212a7e1d060210e70a47e253523"}, {file = "pexpect-4.9.0.tar.gz", hash = "sha256:ee7d41123f3c9911050ea2c2dac107568dc43b2d3b0c7557a33212c398ead30f"}, @@ -926,7 +923,6 @@ description = "Library for building powerful interactive command lines in Python optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "prompt_toolkit-3.0.51-py3-none-any.whl", hash = "sha256:52742911fde84e2d423e2f9a4cf1de7d7ac4e51958f648d9540e0fb8db077b07"}, {file = "prompt_toolkit-3.0.51.tar.gz", hash = "sha256:931a162e3b27fc90c86f1b48bb1fb2c528c2761475e57c9c06de13311c7b54ed"}, @@ -942,7 +938,7 @@ description = "Run a subprocess in a pseudo terminal" optional = false python-versions = "*" groups = ["local"] -markers = "python_version == \"3.9\" and sys_platform != \"win32\" or python_version < \"4.0\" and sys_platform != \"win32\" and sys_platform != \"emscripten\"" +markers = "python_version == \"3.9\" and sys_platform != \"win32\" or sys_platform != \"win32\" and sys_platform != \"emscripten\"" files = [ {file = "ptyprocess-0.7.0-py2.py3-none-any.whl", hash = "sha256:4b41f3967fce3af57cc7e94b888626c18bf37a083e3651ca8feeb66d492fef35"}, {file = "ptyprocess-0.7.0.tar.gz", hash = "sha256:5c5d0a3b48ceee0b48485e0c26037c0acd7d29765ca3fbb5cb3831d347423220"}, @@ -955,7 +951,6 @@ description = "Safely evaluate AST nodes without side effects" optional = false python-versions = "*" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "pure_eval-0.2.3-py3-none-any.whl", hash = "sha256:1db8e35b67b3d218d818ae653e27f06c3aa420901fa7b081ca98cbedc874e0d0"}, {file = "pure_eval-0.2.3.tar.gz", hash = "sha256:5f4e983f40564c576c7c8635ae88db5956bb2229d7e9237d03b3c0b0190eaf42"}, @@ -971,7 +966,6 @@ description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b"}, {file = "pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887"}, @@ -1042,7 +1036,6 @@ description = "pytest-httpserver is a httpserver for pytest" optional = false python-versions = ">=3.9" groups = ["dev"] -markers = "python_version < \"4.0\"" files = [ {file = "pytest_httpserver-1.1.3-py3-none-any.whl", hash = "sha256:5f84757810233e19e2bb5287f3826a71c97a3740abe3a363af9155c0f82fdbb9"}, {file = "pytest_httpserver-1.1.3.tar.gz", hash = "sha256:af819d6b533f84b4680b9416a5b3f67f1df3701f1da54924afd4d6e4ba5917ec"}, @@ -1153,7 +1146,6 @@ description = "Extract data from python stack frames and tracebacks for informat optional = false python-versions = "*" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695"}, {file = "stack_data-0.6.3.tar.gz", hash = "sha256:836a778de4fec4dcd1dcd89ed8abff8a221f58308462e1c4aa2a3cf30148f0b9"}, @@ -1224,14 +1216,14 @@ files = [ [[package]] name = "tox" -version = "4.28.3" +version = "4.28.4" description = "tox is a generic virtualenv management and test command line tool" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "tox-4.28.3-py3-none-any.whl", hash = "sha256:1debe9daf0b7e64d425ef99a17292b0792385686b1d541df34c7298211e99269"}, - {file = "tox-4.28.3.tar.gz", hash = "sha256:b91db7219e5242002cf4040a299c8852026d6af35fcd21274d456fb62dafee7b"}, + {file = "tox-4.28.4-py3-none-any.whl", hash = "sha256:8d4ad9ee916ebbb59272bb045e154a10fa12e3bbdcf94cc5185cbdaf9b241f99"}, + {file = "tox-4.28.4.tar.gz", hash = "sha256:b5b14c6307bd8994ff1eba5074275826620325ee1a4f61316959d562bfd70b9d"}, ] [package.dependencies] @@ -1254,7 +1246,6 @@ description = "Traitlets Python configuration system" optional = false python-versions = ">=3.8" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "traitlets-5.14.3-py3-none-any.whl", hash = "sha256:b74e89e397b1ed28cc831db7aea759ba6640cb3de13090ca145426688ff1ac4f"}, {file = "traitlets-5.14.3.tar.gz", hash = "sha256:9ed0579d3502c94b4b3732ac120375cda96f923114522847de4b3bb98b96b6b7"}, @@ -1310,14 +1301,14 @@ urllib3 = ">=2" [[package]] name = "types-setuptools" -version = "73.0.0.20240822" +version = "80.9.0.20250801" description = "Typing stubs for setuptools" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "types-setuptools-73.0.0.20240822.tar.gz", hash = "sha256:3a060681098eb3fbc2fea0a86f7f6af6aa1ca71906039d88d891ea2cecdd4dbf"}, - {file = "types_setuptools-73.0.0.20240822-py3-none-any.whl", hash = "sha256:b9eba9b68546031317a0fa506d4973641d987d74f79e7dd8369ad4f7a93dea17"}, + {file = "types_setuptools-80.9.0.20250801-py3-none-any.whl", hash = "sha256:ec908f825134af3964932e6b011dce90f54c291015139cd9cdf79741b7d31b3c"}, + {file = "types_setuptools-80.9.0.20250801.tar.gz", hash = "sha256:e1e92682fa07226415396bb4e2d31f116a16ffbe583b05b01f9910fcdea3b7e8"}, ] [[package]] @@ -1423,7 +1414,6 @@ description = "Measures the displayed width of unicode strings in a terminal" optional = false python-versions = "*" groups = ["local"] -markers = "python_version < \"4.0\"" files = [ {file = "wcwidth-0.2.13-py2.py3-none-any.whl", hash = "sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859"}, {file = "wcwidth-0.2.13.tar.gz", hash = "sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5"}, @@ -1470,5 +1460,5 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" -python-versions = ">=3.9" -content-hash = "8d7135c3f6faa54226334f03a9b31f95a06fe047b1651b8340830cb5c0a8e9d1" +python-versions = ">=3.9,<3.14.0" +content-hash = "2f3a7b263114c90adb240073b604b6f282b6e776d294f1848739276d32ff272e" diff --git a/pyproject.toml b/pyproject.toml index 3c884e6..e6600fc 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,13 +26,13 @@ classifiers = [ [tool.poetry.dependencies] # core dependencies -python = ">=3.9" +python = ">=3.9,<3.14.0" urllib3 = ">=1.25.4" -requests = [{version = ">=2.26.0", markers = "python_version<'3.8'"},{version = ">=2.32.0", markers = "python_version>='3.8'"}] -werkzeug = [{version = ">2.0.0", markers = "python_version<'3.8'"},{version = ">=3.0.3", markers = "python_version>='3.8'"}] +requests = ">=2.32.0,<3.0.0" +werkzeug = ">=3.0.3,<4.0.0" [tool.poetry.group.dev.dependencies] -black = [{version = ">=23.0.0", markers = "python_version<'3.8'"},{version = ">=24.0.0", markers = "python_version>='3.8'"}] +black = "^25" mypy = "^1.4.1" types-six = "^1.16.21.8" types-requests = "^2.31.0.1" @@ -41,17 +41,16 @@ mock = "^5.0.2" build = "^1.0.3" toml = "^0.10.2" tox = "^4.6.3" -types-setuptools = {version = "^73.0.0.20240822", python = ">=3.8"} +types-setuptools = "^80" coverage = "^7.2.7" pytest = "^7.4.0" importlib-metadata = {version = ">=4.11.4", python = "<3.12"} -pytest-httpserver = {version = "^1.0.8", python = ">=3.8,<4.0"} +pytest-httpserver = "^1.0.8" ruff = "^0" boto3 = "^1.33.7" [tool.poetry.group.local.dependencies] -ipython = {version = "^8.14.0", python = ">=3.9,<4.0"} - +ipython = "^8.14.0" [tool.ruff] lint.select = [ @@ -107,9 +106,6 @@ include = '\.pyi?$' #)/ #''' - - - [tool.coverage.run] branch = true omit = [ diff --git a/tests/mesh_endpoint_connectivity_tests.py b/tests/mesh_endpoint_connectivity_tests.py index 189b13e..483f0c1 100644 --- a/tests/mesh_endpoint_connectivity_tests.py +++ b/tests/mesh_endpoint_connectivity_tests.py @@ -33,6 +33,8 @@ def _host_resolves(endpoint: Endpoint): CONNECTION_ABORTED_ERROR = "Connection aborted." REMOTE_END_CLOSED_CONNECTION = "Remote end closed connection without response" UNABLE_TO_CONNECT_TO_PROXY = "Unable to connect to proxy" +SSL_CERTIFICATE_ERROR = "SSL certificate error" +LOCAL_HTTPS_PROXY_URL = "http://localhost:8019" @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @@ -82,7 +84,7 @@ def test_hscn_endpoints_defaults_from_hostname(name: str, endpoint: Endpoint): assert err.value.response is not None assert err.value.response.status_code == 400 assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + assert SSL_CERTIFICATE_ERROR in err.value.response.text @pytest.mark.parametrize(("name", "endpoint"), _HSCN_ENDPOINTS) @@ -101,7 +103,7 @@ def test_dep_hscn_endpoint_common_name_check_false(name: str, endpoint: Endpoint else: assert err.value.response is not None assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + assert SSL_CERTIFICATE_ERROR in err.value.response.text assert err.value.response.status_code == 400 @@ -203,7 +205,7 @@ def test_hscn_endpoints_check_hostname(name: str, endpoint: Endpoint, check_host else: assert err.value.response is not None assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + assert SSL_CERTIFICATE_ERROR in err.value.response.text assert err.value.response.status_code == 400 @@ -242,7 +244,7 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), - proxies={"https": "http://localhost:8019"}, + proxies={"https": LOCAL_HTTPS_PROXY_URL}, timeout=10, ) as client, ): @@ -253,7 +255,7 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): else: assert err.value.response is not None assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + assert SSL_CERTIFICATE_ERROR in err.value.response.text assert err.value.response.status_code == 400 @@ -261,7 +263,7 @@ def test_hscn_endpoints_via_an_explicit_proxy(name: str, endpoint: Endpoint): @pytest.mark.skipif(not _host_resolves(DEPRECATED_HSCN_INT_ENDPOINT), reason="these hosts will only resolve on HSCN") def test_hscn_endpoints_via_an_ambient_proxy(name: str, endpoint: Endpoint): with ( - temp_env_vars(HTTPS_PROXY="http://localhost:8019"), + temp_env_vars(HTTPS_PROXY=LOCAL_HTTPS_PROXY_URL), pytest.raises((HTTPError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): @@ -272,7 +274,7 @@ def test_hscn_endpoints_via_an_ambient_proxy(name: str, endpoint: Endpoint): else: assert err.value.response is not None assert err.value.args[0] == f"400 Client Error: Bad Request for url: {endpoint.url}/messageexchange/_ping" - assert "SSL certificate error" in err.value.response.text + assert SSL_CERTIFICATE_ERROR in err.value.response.text assert err.value.response.status_code == 400 @@ -285,7 +287,7 @@ def test_internet_endpoints_via_explicit_proxy(name: str, endpoint: Endpoint): "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY), - proxies={"https": "http://localhost:8019"}, + proxies={"https": LOCAL_HTTPS_PROXY_URL}, ) as client, ): client.handshake() @@ -300,7 +302,7 @@ def test_internet_endpoints_via_explicit_proxy(name: str, endpoint: Endpoint): @pytest.mark.parametrize(("name", "endpoint"), _INTERNET_ENDPOINTS) def test_internet_endpoints_via_ambient_proxy(name: str, endpoint: Endpoint): with ( - temp_env_vars(HTTPS_PROXY="http://localhost:8019"), + temp_env_vars(HTTPS_PROXY=LOCAL_HTTPS_PROXY_URL), pytest.raises((RequestsConnectionError, SSLError)) as err, MeshClient(endpoint, "BADUSERNAME", "BADPASSWORD", cert=(MOCK_CERT, MOCK_KEY)) as client, ): diff --git a/tox.ini b/tox.ini index c9c6068..7d6fc5c 100644 --- a/tox.ini +++ b/tox.ini @@ -19,7 +19,7 @@ wheel_build_env = .pkg use_develop = true package = wheel deps = - requests>=2.26.0 + requests>=2.32.0 mock pytest pytest-httpserver From f3fafae1fbde218df46700cf4180557fc98df2ed Mon Sep 17 00:00:00 2001 From: davidhallam4-nhs <110543996+davidhallam4-nhs@users.noreply.github.com> Date: Mon, 4 Aug 2025 18:15:25 +0100 Subject: [PATCH 5/5] MESH-2092 pin cache key to the python selected in the setup python step --- .github/workflows/merge-develop.yml | 2 +- .github/workflows/pull-request.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/merge-develop.yml b/.github/workflows/merge-develop.yml index 0ae7767..36aa75d 100644 --- a/.github/workflows/merge-develop.yml +++ b/.github/workflows/merge-develop.yml @@ -34,7 +34,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 5e0c5a0..079ec35 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -111,7 +111,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard @@ -229,7 +229,7 @@ jobs: with: path: | .venv - key: ${{ runner.os }}-v3-poetry-py3.9-${{ hashFiles('./poetry.lock') }} + key: ${{ runner.os }}-v3-poetry-py${{ steps.setup-python.outputs.python-version }}-${{ hashFiles('./poetry.lock') }} - name: git reset run: git reset --hard