diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..edbcffe --- /dev/null +++ b/.coveragerc @@ -0,0 +1,5 @@ +[run] +parallel = True +source = cf_remote +concurrency = multiprocessing +sigterm = True diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml new file mode 100644 index 0000000..99ea25e --- /dev/null +++ b/.github/workflows/coverage.yml @@ -0,0 +1,37 @@ +name: Fetch and upload coverage + +permissions: + id-token: write +on: + push: + branches: [master] + pull_request: + branches: [master] +jobs: + coverage: + if: contains(fromJSON('["cfengine","mendersoftware","NorthernTechHQ"]'), github.repository_owner) + runs-on: ubuntu-latest + name: setup-python + env: + PYTHON_VERSION: "3.10" + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - uses: actions/setup-python@v7 + with: + python-version: ${{ env.PYTHON_VERSION }} + - name: Install requirements + run: | + python -m pip install --upgrade pip + python -m pip install uv + uv lock --check + uv sync + - name: Run tests and collect coverage + run: make coverage + - name: Upload coverage reports to Codecov with GitHub Action + uses: codecov/codecov-action@v7 + with: + use_oidc: true + env: + fail_ci_if_error: true diff --git a/.gitignore b/.gitignore index 8069798..632c663 100644 --- a/.gitignore +++ b/.gitignore @@ -5,5 +5,11 @@ dist /cf_remote.egg-info/ /venv /.venv +log __pycache__/ **/.DS_STORE + +# coverage +.coverage.* +.coverage +coverage.xml diff --git a/Makefile b/Makefile index 80d3c91..c5b895d 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,4 @@ -.PHONY: default format lint install check venv +.PHONY: default format lint install check venv coverage default: check @@ -20,3 +20,15 @@ install: check: venv format lint uv run pytest + +export COVERAGE_PROCESS_START = $(PWD)/.coveragerc +export COVERAGE_FILE = $(PWD)/.coverage +coverage: + uv run coverage erase + uv run coverage run --parallel-mode -m pytest + uv run bash tests/shell/all.sh + uv run bash tests/docker/0*.sh + uv run bash tests/unsafe/0*.sh + uv run coverage combine + uv run coverage report --fail-under=40 + uv run coverage xml diff --git a/pyproject.toml b/pyproject.toml index ae5344b..e89fe89 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -43,4 +43,5 @@ dev = [ "pyflakes>=3.2.0", "pyright>=1.1.390", "pytest>=8.3.4", + "coverage; python_version >= '3.10'", ] diff --git a/tests/test_utils.py b/tests/test_utils.py index 06015f8..2edf9ea 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -1,6 +1,6 @@ import os import shutil -from multiprocessing import Pool +import multiprocessing from cf_remote.utils import has_unescaped_character, parse_envfile, copy_file @@ -73,7 +73,12 @@ def test_copy_file(): num_processes = 10 - with Pool(num_processes) as copy_pool: + # Use "spawn" instead of the platform-default "fork": forking a process + # that has other threads running (e.g. coverage's own writer thread) can + # deadlock intermittently if a lock is held mid-fork. Spawn starts each + # worker from a clean interpreter and avoids that. + ctx = multiprocessing.get_context("spawn") + with ctx.Pool(num_processes) as copy_pool: copy_pool.map(copy_file_with_args, [(src, dest) for _ in range(num_processes)]) content = None diff --git a/uv.lock b/uv.lock index 2e281fa..a7b1792 100644 --- a/uv.lock +++ b/uv.lock @@ -19,7 +19,7 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "requests", version = "2.32.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version != '3.9.*'" }, { name = "requests", version = "2.32.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/1b/45/1a239d9789c75899df8ff53a6b198c1657328f3b333f1711194643d53868/apache-libcloud-3.8.0.tar.gz", hash = "sha256:75bf4c0b123bc225e24ca95fca1c35be30b19e6bb85feea781404d43c4276c91", size = 2457665, upload-time = "2023-08-10T08:07:07.45Z" } @@ -35,7 +35,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "requests", version = "2.34.2", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/f0/ed/555a1869de19413efc270078632a8f9a049828ab65f2cc09fd61e6ba3f15/apache_libcloud-3.9.1.tar.gz", hash = "sha256:b65eaa5ac32b28a0f9555e6a223dba39e73b99b682cd849624587ce7bc251661", size = 2582796, upload-time = "2026-04-21T07:09:45.939Z" } wheels = [ @@ -50,13 +50,13 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "mypy-extensions", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "packaging", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "pathspec", version = "0.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "tomli", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" } }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec", version = "0.12.1", source = { registry = "https://pypi.org/simple" } }, + { name = "platformdirs", version = "4.3.6", source = { registry = "https://pypi.org/simple" } }, + { name = "tomli" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/04/b0/46fb0d4e00372f4a86a6f8efa3cb193c9f64863615e39010b1477e010578/black-24.8.0.tar.gz", hash = "sha256:2500945420b6784c38b9ee885af039f5e7471ef284ab03fa35ecdde4688cd83f", size = 644810, upload-time = "2024-08-02T17:43:18.405Z" } wheels = [ @@ -91,14 +91,14 @@ resolution-markers = [ "python_full_version == '3.9.*'", ] dependencies = [ - { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "mypy-extensions", marker = "python_full_version == '3.9.*'" }, - { name = "packaging", marker = "python_full_version == '3.9.*'" }, - { name = "pathspec", version = "1.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "pytokens", marker = "python_full_version == '3.9.*'" }, - { name = "tomli", marker = "python_full_version == '3.9.*'" }, - { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, + { name = "click", version = "8.1.8", source = { registry = "https://pypi.org/simple" } }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec", version = "1.1.1", source = { registry = "https://pypi.org/simple" } }, + { name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" } }, + { name = "pytokens" }, + { name = "tomli" }, + { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/8c/ad/33adf4708633d047950ff2dfdea2e215d84ac50ef95aff14a614e4b6e9b2/black-25.11.0.tar.gz", hash = "sha256:9a323ac32f5dc75ce7470501b887250be5005a01602e931a15e45593f70f6e08", size = 655669, upload-time = "2025-11-10T01:53:50.558Z" } wheels = [ @@ -137,14 +137,14 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "click", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "mypy-extensions", marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "pathspec", version = "1.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "platformdirs", version = "4.10.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pytokens", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, - { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "click", version = "8.4.2", source = { registry = "https://pypi.org/simple" } }, + { name = "mypy-extensions" }, + { name = "packaging" }, + { name = "pathspec", version = "1.1.1", source = { registry = "https://pypi.org/simple" } }, + { name = "platformdirs", version = "4.10.0", source = { registry = "https://pypi.org/simple" } }, + { name = "pytokens" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, + { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c0/37/5628dd55bf2b34257fc7603f0fe97c40e3aaf24265f416a9c85c95ca1436/black-26.5.1.tar.gz", hash = "sha256:dd321f668053961824bcc1be1cc1df748b2d7e4fa28086b08331e577b0100a73", size = 679439, upload-time = "2026-05-18T16:53:36.107Z" } wheels = [ @@ -189,24 +189,24 @@ wheels = [ name = "cf-remote" source = { editable = "." } dependencies = [ - { name = "apache-libcloud", version = "3.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.10'" }, + { name = "apache-libcloud", version = "3.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "apache-libcloud", version = "3.9.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] [package.dev-dependencies] dev = [ - { name = "black", version = "24.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "black", version = "24.8.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "black", version = "25.11.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "black", version = "26.5.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "coverage", version = "7.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "coverage", version = "7.6.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "coverage", version = "7.10.7", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "coverage", version = "7.15.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "flake8", version = "7.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "flake8", version = "7.1.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "flake8", version = "7.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "pyflakes", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "pyflakes", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "pyflakes", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "pyright", marker = "python_full_version >= '3.8.1'" }, - { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "pyright" }, + { name = "pytest", version = "8.3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "pytest", version = "8.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, { name = "pytest", version = "9.1.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, ] @@ -218,6 +218,7 @@ requires-dist = [{ name = "apache-libcloud", specifier = ">=3.3.1" }] dev = [ { name = "black", specifier = ">=24.8.0" }, { name = "coverage", specifier = ">=7.6.1" }, + { name = "coverage", marker = "python_full_version >= '3.10'" }, { name = "flake8", specifier = ">=7.1.2" }, { name = "pyflakes", specifier = ">=3.2.0" }, { name = "pyright", specifier = ">=1.1.390" }, @@ -369,7 +370,7 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.8.1' and python_full_version < '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" } wheels = [ @@ -384,7 +385,7 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/76/d4/81420972a676e8ffea40450d8c8c92943e7218a78fe9b64359836cc9876b/click-8.4.2.tar.gz", hash = "sha256:9a6cea6e60b17ebe0a44c5cc636d94f09bd66142c1cd7d8b4cd731c4917a15f6", size = 338000, upload-time = "2026-06-24T17:45:15.148Z" } wheels = [ @@ -702,8 +703,8 @@ name = "exceptiongroup" version = "1.3.1" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.13'" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9' or python_full_version >= '3.11'" }, + { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9' and python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/50/79/66800aadf48771f6b62f7eb014e352e5d06856655206165d775e675a02c9/exceptiongroup-1.3.1.tar.gz", hash = "sha256:8b412432c6055b0b7d14c310000ae93352ed6754f70fa8f7c34141f91c4e3219", size = 30371, upload-time = "2025-11-21T23:01:54.787Z" } wheels = [ @@ -718,9 +719,9 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "mccabe", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "pycodestyle", version = "2.12.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "pyflakes", version = "3.2.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "mccabe" }, + { name = "pycodestyle", version = "2.12.1", source = { registry = "https://pypi.org/simple" } }, + { name = "pyflakes", version = "3.2.0", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/58/16/3f2a0bb700ad65ac9663262905a025917c020a3f92f014d2ba8964b4602c/flake8-7.1.2.tar.gz", hash = "sha256:c586ffd0b41540951ae41af572e6790dbd49fc12b3aa2541685d253d9bd504bd", size = 48119, upload-time = "2025-02-16T18:45:44.296Z" } wheels = [ @@ -736,9 +737,9 @@ resolution-markers = [ "python_full_version == '3.9.*'", ] dependencies = [ - { name = "mccabe", marker = "python_full_version >= '3.9'" }, - { name = "pycodestyle", version = "2.14.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, - { name = "pyflakes", version = "3.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, + { name = "mccabe" }, + { name = "pycodestyle", version = "2.14.0", source = { registry = "https://pypi.org/simple" } }, + { name = "pyflakes", version = "3.4.0", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/9b/af/fbfe3c4b5a657d79e5c47a2827a362f9e1b763336a52f926126aa6dc7123/flake8-7.3.0.tar.gz", hash = "sha256:fe044858146b9fc69b551a4b490d69cf960fcb78ad1edcb84e7fbb1b4a8e3872", size = 48326, upload-time = "2025-06-20T19:31:35.838Z" } wheels = [ @@ -981,8 +982,8 @@ name = "pyright" version = "1.1.411" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "nodeenv", marker = "python_full_version >= '3.8.1'" }, - { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "nodeenv" }, + { name = "typing-extensions", version = "4.13.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.9'" }, { name = "typing-extensions", version = "4.16.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.9'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/7e/ab/265f7dc69d28113ebba19092e57b075f41543b2ed048429c5f56e2b88eac/pyright-1.1.411.tar.gz", hash = "sha256:d885a0551f2e763b089a02702174e7f4ba77548cddabc972ab86d1f7f1b0f998", size = 4112861, upload-time = "2026-06-25T02:14:06.37Z" } @@ -998,12 +999,12 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9' and sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "packaging", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "tomli", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging" }, + { name = "pluggy", version = "1.5.0", source = { registry = "https://pypi.org/simple" } }, + { name = "tomli" }, ] sdist = { url = "https://files.pythonhosted.org/packages/ae/3c/c9d525a414d506893f0cd8a8d0de7706446213181570cdbd766691164e40/pytest-8.3.5.tar.gz", hash = "sha256:f4efe70cc14e511565ac476b57c279e12a855b11f48f212af1080ef2263d3845", size = 1450891, upload-time = "2025-03-02T12:54:54.503Z" } wheels = [ @@ -1018,13 +1019,13 @@ resolution-markers = [ "python_full_version == '3.9.*'", ] dependencies = [ - { name = "colorama", marker = "python_full_version == '3.9.*' and sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version == '3.9.*'" }, - { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "packaging", marker = "python_full_version == '3.9.*'" }, - { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "pygments", marker = "python_full_version == '3.9.*'" }, - { name = "tomli", marker = "python_full_version == '3.9.*'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup" }, + { name = "iniconfig", version = "2.1.0", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging" }, + { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" } }, + { name = "pygments" }, + { name = "tomli" }, ] sdist = { url = "https://files.pythonhosted.org/packages/a3/5c/00a0e072241553e1a7496d638deababa67c5058571567b92a7eaa258397c/pytest-8.4.2.tar.gz", hash = "sha256:86c0d0b93306b961d58d62a4db4879f27fe25513d4b969df351abdddb3c30e01", size = 1519618, upload-time = "2025-09-04T14:34:22.711Z" } wheels = [ @@ -1039,13 +1040,13 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" }, - { name = "exceptiongroup", marker = "python_full_version == '3.10.*'" }, - { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "packaging", marker = "python_full_version >= '3.10'" }, - { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "pygments", marker = "python_full_version >= '3.10'" }, - { name = "tomli", marker = "python_full_version == '3.10.*'" }, + { name = "colorama", marker = "sys_platform == 'win32'" }, + { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, + { name = "iniconfig", version = "2.3.0", source = { registry = "https://pypi.org/simple" } }, + { name = "packaging" }, + { name = "pluggy", version = "1.6.0", source = { registry = "https://pypi.org/simple" } }, + { name = "pygments" }, + { name = "tomli", marker = "python_full_version < '3.11'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz", hash = "sha256:1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313", size = 1636369, upload-time = "2026-06-19T10:58:32.857Z" } wheels = [ @@ -1109,10 +1110,10 @@ resolution-markers = [ "python_full_version >= '3.8.1' and python_full_version < '3.9'", ] dependencies = [ - { name = "certifi", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "charset-normalizer", marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "idna", version = "3.15", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, - { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.8.1' and python_full_version < '3.9'" }, + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna", version = "3.15", source = { registry = "https://pypi.org/simple" } }, + { name = "urllib3", version = "2.2.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } wheels = [ @@ -1127,10 +1128,10 @@ resolution-markers = [ "python_full_version == '3.9.*'", ] dependencies = [ - { name = "certifi", marker = "python_full_version == '3.9.*'" }, - { name = "charset-normalizer", marker = "python_full_version == '3.9.*'" }, - { name = "idna", version = "3.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, - { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.9.*'" }, + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna", version = "3.18", source = { registry = "https://pypi.org/simple" } }, + { name = "urllib3", version = "2.6.3", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/c9/74/b3ff8e6c8446842c3f5c837e9c3dfcfe2018ea6ecef224c710c85ef728f4/requests-2.32.5.tar.gz", hash = "sha256:dbba0bac56e100853db0ea71b82b4dfd5fe2bf6d3754a8893c3af500cec7d7cf", size = 134517, upload-time = "2025-08-18T20:46:02.573Z" } wheels = [ @@ -1145,10 +1146,10 @@ resolution-markers = [ "python_full_version >= '3.10'", ] dependencies = [ - { name = "certifi", marker = "python_full_version >= '3.10'" }, - { name = "charset-normalizer", marker = "python_full_version >= '3.10'" }, - { name = "idna", version = "3.18", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, - { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna", version = "3.18", source = { registry = "https://pypi.org/simple" } }, + { name = "urllib3", version = "2.7.0", source = { registry = "https://pypi.org/simple" } }, ] sdist = { url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz", hash = "sha256:f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed", size = 142856, upload-time = "2026-05-14T19:25:27.735Z" } wheels = [