diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index 1405372..b2c91b0 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1,3 +1,2 @@
---
github: hynek
-ko_fi: the_hynek
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
index e259ce4..fd89895 100644
--- a/.github/dependabot.yml
+++ b/.github/dependabot.yml
@@ -1,6 +1,4 @@
-# Please see the documentation for all configuration options:
-# https://docs.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
+---
version: 2
updates:
- package-ecosystem: github-actions
diff --git a/.github/logo.png b/.github/logo.png
new file mode 100644
index 0000000..63046a3
Binary files /dev/null and b/.github/logo.png differ
diff --git a/.github/workflows/ci-supported-pythons.yml b/.github/workflows/ci-supported-pythons.yml
new file mode 100644
index 0000000..a480d6c
--- /dev/null
+++ b/.github/workflows/ci-supported-pythons.yml
@@ -0,0 +1,93 @@
+---
+name: Use JSON output to build job matrix
+
+on:
+ push:
+ branches: [main]
+ pull_request:
+ workflow_dispatch:
+
+env:
+ FORCE_COLOR: "1" # Make tools pretty.
+
+jobs:
+ build-package:
+ name: Build & verify package
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ repository: hynek/structlog
+ path: structlog
+ fetch-depth: 0
+ - uses: actions/checkout@v4
+ with:
+ path: action
+ - uses: ./action
+ id: baipp
+ with:
+ path: structlog
+
+ outputs:
+ package-version: ${{ steps.baipp.outputs.package_version }}
+ python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_array }}
+ # If your matrix consists only of Python versions, you can use the
+ # following, too:
+ # python-versions: ${{ steps.baipp.outputs.supported_python_classifiers_json_job_matrix_value }}
+
+ test-supported-pythons:
+ needs: build-package
+ runs-on: ubuntu-latest
+ strategy:
+ matrix:
+ # Create matrix from the 'python-versions' output from the build-package
+ # job.
+ python-version: ${{ fromJson(needs.build-package.outputs.python-versions) }}
+
+ # If you set 'python-versions' to
+ # 'supported_python_classifiers_json_job_matrix_value'
+ # above, you would set the matrix like this instead:
+ # matrix: ${{ fromJson(needs.build-package.outputs.python-versions) }}
+
+ steps:
+ - uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+ allow-prereleases: true
+
+ - name: Download built packages from the build-package job.
+ uses: actions/download-artifact@v4
+ with:
+ name: Packages
+ path: dist
+
+ - name: Prepare tests & config
+ run: |
+ # We use tox together with the fast tox-uv plugin.
+ python -Im pip install tox-uv
+
+ # Unpack SDist for tests & config files.
+ tar xf dist/*.tar.gz --strip-components=1
+
+ # Ensure tests run against wheel.
+ rm -rf src
+
+ # To conserve CI resources, we've commented the next step out to not
+ # actually run the tests. Just remove the 'echo' to run them.
+ - name: Run tox environments for ${{ matrix.python-version }}
+ run: echo python -Im tox run --installpkg dist/*.whl -f py$(echo ${{ matrix.python-version }} | tr -d .)
+
+ test-package-version:
+ needs: build-package
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/setup-python@v5
+ with:
+ python-version: "3.x"
+
+ - run: |
+ echo "Package version: ${{ needs.build-package.outputs.package-version }}"
+
+...
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index b99db61..4373cfc 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -5,25 +5,53 @@ on:
push:
branches: [main]
pull_request:
- branches: [main]
workflow_dispatch:
env:
FORCE_COLOR: "1" # Make tools pretty.
SETUPTOOLS_SCM_PRETEND_VERSION: "1.0" # avoid warnings about shallow checkout
+ UV_SYSTEM_PYTHON: "true" # ensure action can deal with this set
jobs:
+ check-argon2-cffi-bindings:
+ name: Build & verify the argon2-cffi-bindings package.
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ repository: hynek/argon2-cffi-bindings
+ submodules: recursive
+ path: hynek/argon2-cffi-bindings
+
+ - uses: actions/checkout@v4
+ with:
+ path: action
+
+ - uses: ./action
+ id: baipp
+ with:
+ path: hynek/argon2-cffi-bindings
+ skip-wheel: 'true'
+
check-structlog:
name: Build & verify the structlog package.
- runs-on: ubuntu-latest
+ runs-on: ${{ matrix.os }}
+ strategy:
+ fail-fast: false
+ matrix:
+ os:
+ - ubuntu-20.04
+ - ubuntu-22.04
+ - ubuntu-24.04
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
repository: hynek/structlog
path: structlog
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
path: action
@@ -31,25 +59,45 @@ jobs:
id: baipp
with:
path: structlog
+ upload-name-suffix: "-structlog-${{ matrix.os }}"
- - run: echo Packages can be found at ${{ steps.baipp.outputs.dist }}
+ - run: echo Packages can be found at ${{ steps.baipp.outputs.dist }} and in artifact ${{ steps.baipp.outputs.artifact-name }}
- check-argon2-cffi-bindings:
- name: Build & verify the argon2-cffi-bindings package.
+ check-pytest:
+ name: Build & verify the pytest package.
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
- repository: hynek/argon2-cffi-bindings
- submodules: recursive
- path: hynek/argon2-cffi-bindings
+ repository: pytest-dev/pytest
+ path: pytest
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
with:
path: action
- uses: ./action
id: baipp
with:
- path: hynek/argon2-cffi-bindings
+ path: pytest
+ upload-name-suffix: "-pytest"
+
+ - run: echo Packages can be found at ${{ steps.baipp.outputs.dist }} and in artifact ${{ steps.baipp.outputs.artifact-name }}
+
+ required-checks-pass:
+ name: Ensure everything required is passing for branch protection
+ if: always()
+
+ needs:
+ - check-argon2-cffi-bindings
+ - check-structlog
+ - check-pytest
+
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Decide whether the needed jobs succeeded or failed
+ uses: re-actors/alls-green@release/v1
+ with:
+ jobs: ${{ toJSON(needs) }}
diff --git a/.github/workflows/upgrade-dependencies.yml b/.github/workflows/update-dependencies.yml
similarity index 84%
rename from .github/workflows/upgrade-dependencies.yml
rename to .github/workflows/update-dependencies.yml
index 83f4f2e..637abd6 100644
--- a/.github/workflows/upgrade-dependencies.yml
+++ b/.github/workflows/update-dependencies.yml
@@ -1,4 +1,4 @@
-name: Upgrade dependencies
+name: Update dependencies
# Stolen from https://www.oddbird.net/2022/06/01/dependabot-single-pull-request/
@@ -17,20 +17,20 @@ jobs:
# It doesn't matter if it's deleted when merged, it'll be re-created
BRANCH_NAME: auto-dependency-upgrades
steps:
- - uses: actions/checkout@v3
+ - uses: actions/checkout@v4
# START PYTHON DEPENDENCIES
- - uses: actions/setup-python@v3
- with:
- python-version: "3.10"
- cache: pip
- cache-dependency-path: "**/pip-tools.txt"
+ - name: Install uv
+ run: curl -LsSf https://astral.sh/uv/install.sh | sh
- name: Upgrade Python dependencies
# ADD YOUR CUSTOM DEPENDENCY UPGRADE COMMANDS BELOW
- run: |
- pip install -U pip pip-tools
- pip-compile --upgrade -o requirements/tools.txt requirements/tools.in
+ run: >
+ uv pip compile
+ --upgrade
+ --generate-hashes
+ --output-file=requirements/tools.txt
+ requirements/tools.in
# END PYTHON DEPENDENCIES
- name: Detect changes
id: changes
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 1036022..ae2c600 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -4,7 +4,7 @@ ci:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
- rev: v4.4.0
+ rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 4e56b10..b2e7f77 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -5,12 +5,215 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
-## [1.5](https://github.com/hynek/build-and-inspect-python-package/compare/v1.4.1...v1.5)
+## [2.12.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.11.0...v2.12.0)
+
+### Changed
+
+- This release only updates the tools we use.
+ It's important for being able to handle packaging metadata 2.4, as published by recent versions of Hatchling, though.
+ [#161](https://github.com/hynek/build-and-inspect-python-package/pull/161)
+
+
+## [2.11.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.10.0...v2.11.0)
+
+### Added
+
+- New output: `package_version` is the version of the package that was built.
+ [#152](https://github.com/hynek/build-and-inspect-python-package/pull/152)
+
+
+## [2.10.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.9.0...2.10.0)
+
+### Changed
+
+- Remove `.gitignore` from the build target directory to avoid [silly attestations](https://github.com/hynek/svcs/attestations/2821122).
+ [#149](https://github.com/hynek/build-and-inspect-python-package/pull/149)
+
+
+## [2.9.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.8.0...v2.9.0)
+
+### Changed
+
+- `uv build` is now used instead of the [*build*](https://pypi.org/project/build/) package.
+ Since the actual build of the packages is done by the packaging backend (the one you define in your `pyproject.toml` under `build-system.build-backend` -- for example, Setuptools or Hatchling), this should make no difference except for faster runs.
+ [#140](https://github.com/hynek/build-and-inspect-python-package/pull/140)
+
+
+## [2.8.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.7.0...v2.8.0) - 2024-07-25
+
+### Changed
+
+- Use *uv*'s new `uv cache prune --ci` to only cache downloaded files.
+ This makes the cache smaller and faster to pack/unpack.
+ [#135](https://github.com/hynek/build-and-inspect-python-package/pull/135)
+
+
+### Fixed
+
+- Turns out, the default location of *uv*'s cache cannot be cached and [*actions/cache*](https://github.com/actions/cache) fails silently with an opaque "Path(s) specified in the action for caching do(es) not exist, hence no cache is being saved." log message.
+ We have moved the cache to `/tmp`.
+ [#135](https://github.com/hynek/build-and-inspect-python-package/pull/135)
+
+
+## [2.7.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.6.0...v2.7.0) - 2024-07-17
+
+### Added
+
+- A header before package contents in the summary.
+ Especially useful together with a preceding build provenance attestation.
+ [#131](https://github.com/hynek/build-and-inspect-python-package/pull/131)
+
+
+## [2.6.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.5.0...v2.6.0) - 2024-05-26
+
+### Added
+
+- Support for `ubuntu-24.04` builders.
+ [#126](https://github.com/hynek/build-and-inspect-python-package/pull/126)
+
+- New output: `artifact-name` is the name of the uploaded artifact.
+ [#125](https://github.com/hynek/build-and-inspect-python-package/pull/125)
+
+
+## [2.5.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.4.0...v2.5.0) - 2024-05-13
+
+### Added
+
+- New input: `attest-build-provenance-github` generates signed build provenance attestations for workflow artifacts.
+ [#122](https://github.com/hynek/build-and-inspect-python-package/pull/122)
+
+
+## [2.4.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.3.0...v2.4.0) - 2024-04-11
+
+### Changed
+
+- The action doesn't crash anymore if the user sets globally the `UV_SYSTEM_PYTHON` environment variable.
+[#116](https://github.com/hynek/build-and-inspect-python-package/pull/116)
+
+
+## [2.3.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.2.1...v2.3.0) - 2024-04-11
+
+### Added
+
+- Cache busting for the *uv* cache.
+ GitHub Actions's caching behavior is a bit idiosyncratic:
+ Once a cache is created, it's immutable.
+ But as long as it's accessed within 7 days, it never goes away.
+
+ Therefore, *baipp* now uses the hash of the requirements file as part of the cache key.
+ Behaviorally, nothing changes, except that the cache doesn't grow useless over time.
+ [#115](https://github.com/hynek/build-and-inspect-python-package/pull/115)
+
+
+## [2.2.1](https://github.com/hynek/build-and-inspect-python-package/compare/v2.2.0...v2.2.1) - 2024-04-02
+
+### Fixed
+
+- The action uses *wheel* to unpack wheels again (this is a revert of [#103](https://github.com/hynek/build-and-inspect-python-package/pull/103)) due to [incompatibilities](https://github.com/hynek/build-and-inspect-python-package/issues/113) with, for example, *pytest*.
+ To avoid the confusion due to wrong timestamps, the wheel's tree output in the Summary has no timestamps anymore.
+ [#114](https://github.com/hynek/build-and-inspect-python-package/pull/114)
+
+
+## [2.2.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.1.0...v2.2.0) - 2024-03-31
+
+### Changed
+
+- Use *uv* as installer command for *build* for further speedups.
+ [#107](https://github.com/hynek/build-and-inspect-python-package/pull/107)
+
+
+## [2.1.0](https://github.com/hynek/build-and-inspect-python-package/compare/v2.0.2...2.1.0) - 2024-03-27
+
+### Added
+
+- New outputs: `supported_python_classifiers_json_array` and `supported_python_classifiers_json_job_matrix_value`.
+
+ They are extracted from the trove classifiers defined in the package metadata (for example, `Programming Language :: Python :: 3.12`) and allow you to define the Python versions matrix for your CI jobs without duplicating this information.
+ [#80](https://github.com/hynek/build-and-inspect-python-package/pull/80)
+ [#102](https://github.com/hynek/build-and-inspect-python-package/pull/102)
+
+- New input: `skip-wheel` to skip building the wheel in addition to the source distribution.
+ This is useful if you need to build your wheels using advanced tools like [*cibuildwheel*](https://cibuildwheel.pypa.io/) anyway.
+ [#98](https://github.com/hynek/build-and-inspect-python-package/pull/98)
+
+- New input: `upload-name-suffix` allows to build more than one package in a single workflow by distinguishing the artifact names.
+ [#97](https://github.com/hynek/build-and-inspect-python-package/pull/97)
+
+
+### Changed
+
+- The action now uses [*uv*](https://github.com/astral-sh/uv) to install its tools to speed up your CI runs.
+ [#86](https://github.com/hynek/build-and-inspect-python-package/pull/86)
+
+- We now use `unzip` to extract wheels, which preserves timestamps in the "Wheel contents" summary.
+ [#103](https://github.com/hynek/build-and-inspect-python-package/pull/103)
+
+
+## [2.0.2](https://github.com/hynek/build-and-inspect-python-package/compare/v2.0.1...v2.0.2) – 2024-03-16
+
+### Changed
+
+- Dependency updates for Metadata-Version 2.3 support (as used, for example, by [Hatchling 1.22.1](https://github.com/pypa/hatch/releases/tag/hatchling-v1.22.1)).
+
+
+## [2.0.1](https://github.com/hynek/build-and-inspect-python-package/compare/v2.0.0...v2.0.1) - 2024-01-25
+
+### Changed
+
+- Switched to `setup-python@v5` to avoid the "Node.js 16 actions are deprecated." deprecation warning.
+
+
+## [2.0.0](https://github.com/hynek/build-and-inspect-python-package/compare/v1.5.4...v2.0.0) - 2023-12-15
+
+### Changed
+
+- Switched to using v4 of `actions/upload-artifact`.
+ This version is incompatible with older versions of `actions/download-artifact` -- hence the major version bump.
+ See also [GitHub's announcement](https://github.blog/changelog/2023-12-14-github-actions-artifacts-v4-is-now-generally-available/).
+ [#78](https://github.com/hynek/build-and-inspect-python-package/pull/78)
+
+
+## [1.5.4](https://github.com/hynek/build-and-inspect-python-package/compare/v1.5.3...v1.5.4) - 2023-11-01
+
+### Fixed
+
+- Stop trying to cache.
+ Fixes `Error: No file in /home/runner/work/pytest-cpp/pytest-cpp matched to [**/requirements.txt or **/pyproject.toml], make sure you have checked out the target repository`
+ [#76](https://github.com/hynek/build-and-inspect-python-package/pull/76)
+
+
+## [1.5.3](https://github.com/hynek/build-and-inspect-python-package/compare/v1.5.1...1.5.3) - 2023-10-27
+
+### Changed
+
+- Hopefully nothing, but this release comes from the main branch again.
+
+
+## [1.5.2](https://github.com/hynek/build-and-inspect-python-package/compare/v1.5...v1.5.2) - 2023-10-27
+
+### Fixed
+
+- Turns out it made a huge difference.
+ This release is branched directly from v1.5 and only updates the dependencies.
+
+
+## [1.5.1](https://github.com/hynek/build-and-inspect-python-package/compare/v1.5...v1.5.1) - 2023-10-27
+
+### Changed
+
+- Updates of the tools we use.
+ Notably this fixes *check-wheel-contents* on Python 3.12.
+
+- This shouldn't make any difference, but all management and command running is now done by [PDM](https://pdm.fming.dev/).
+ [#57](https://github.com/hynek/build-and-inspect-python-package/pull/57)
+
+
+## [1.5.0](https://github.com/hynek/build-and-inspect-python-package/compare/v1.4.1...v1.5.0) - 2023-02-09
### Added
- Set [`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/specs/source-date-epoch/) based on the timestamp of the last commit for build reproducibility.
- [#30](https://github.com/hynek/build-and-inspect-python-package/pull/18)
+ [#30](https://github.com/hynek/build-and-inspect-python-package/pull/30)
- The *tree* output now has ISO timestamps.
@@ -20,14 +223,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
As of writing, that's 3.11.
-## [1.4.1](https://github.com/hynek/build-and-inspect-python-package/compare/v1.4...v1.4.1)
+## [1.4.1](https://github.com/hynek/build-and-inspect-python-package/compare/v1.4...v1.4.1) - 2022-10-13
### Fixed
- Doesn't raise a [deprecation warning](https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/) re: `set-output` anymore.
-## [1.4](https://github.com/hynek/build-and-inspect-python-package/compare/v1.3...v1.4)
+## [1.4](https://github.com/hynek/build-and-inspect-python-package/compare/v1.3...v1.4) - 2022-10-13
### Added
@@ -42,7 +245,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[#18](https://github.com/hynek/build-and-inspect-python-package/pull/18)
-## [1.3](https://github.com/hynek/build-and-inspect-python-package/compare/v1.2...v1.3)
+## [1.3](https://github.com/hynek/build-and-inspect-python-package/compare/v1.2...v1.3) - 2022-08-24
### Added
@@ -52,7 +255,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[#11](https://github.com/hynek/build-and-inspect-python-package/pull/11)
-## [1.2](https://github.com/hynek/build-and-inspect-python-package/compare/v1.1...v1.2)
+## [1.2](https://github.com/hynek/build-and-inspect-python-package/compare/v1.1...v1.2) - 2022-08-21
### Added
@@ -60,7 +263,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[#9](https://github.com/hynek/build-and-inspect-python-package/pull/9)
-## [1.1](https://github.com/hynek/build-and-inspect-python-package/compare/v1.0...v1.1)
+## [1.1](https://github.com/hynek/build-and-inspect-python-package/compare/v1.0...v1.1) - 2022-08-20
### Changed
@@ -68,7 +271,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
[#7](https://github.com/hynek/build-and-inspect-python-package/pull/7)
-## [1.0](https://github.com/hynek/build-and-inspect-python-package/compare/v0.1...v1.0)
+## [1.0](https://github.com/hynek/build-and-inspect-python-package/compare/v0.1...v1.0) - 2022-08-20
### Changed
diff --git a/README.md b/README.md
index 8e1c62e..630dcb2 100644
--- a/README.md
+++ b/README.md
@@ -1,69 +1,214 @@
-# build-and-inspect-python-package
+
+
+
+ Never upload a faulty Python package to PyPI again.
+
-This action provides the following functionality for GitHub Actions users that are maintaining Python packages:
+*build-and-inspect-python-package* is a GitHub Action that provides the following functionality to Python package maintainers:
-**Builds your package** using PyPA's [*build*](https://pypi.org/project/build/) (this works with any [PEP 517](https://peps.python.org/pep-0517/)-compatible build backend, including Hatch, Flit, Setuptools, PDM, or Poetry).
-[`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/specs/source-date-epoch/) is set to the timestamp of the last commit, giving you reproducible builds with sensible file timestamps.
+**Builds your package**[^backend].
+[`SOURCE_DATE_EPOCH`](https://reproducible-builds.org/specs/source-date-epoch/) is set to the timestamp of the last commit, giving you reproducible builds with meaningful file timestamps.
+
+[^backend]: Works with any [PEP 517](https://peps.python.org/pep-0517/)-compatible build backend. This includies Hatchling, Flit, Setuptools, PDM, and Poetry.
Uploads the **built *wheel* and the source distribution (*SDist*) as GitHub Actions artifacts**, so you can download and inspect them from the Summary view of a run, or [**upload them to PyPI automatically**][automated] once the verification succeeds.
Lints the **wheel contents** using [*check-wheel-contents*](https://pypi.org/project/check-wheel-contents/).
-Lints the **PyPI README** using [Twine](https://pypi.org/project/twine/) and uploads it as an GitHub Actions artifact for further inspection.
+Lints the **PyPI README** using [Twine](https://pypi.org/project/twine/) and uploads it as an GitHub Actions artifact for further manual inspection.
To level up your PyPI README game, check out [*hatch-fancy-pypi-readme*](https://github.com/hynek/hatch-fancy-pypi-readme)!
-Prints the **tree of both *SDist* and *wheel*** in the CI output, so you don't have to download the packages, if you just want to check the content list.
+Prints the **tree of both *SDist* and *wheel*** in the CI output, so you don’t have to download the packages, if you just want to check the content list.
Prints and uploads the **packaging metadata** as a GitHub Actions artifact.
----
-If you package an **application** as a Python package, this action is useful to double-check you're shipping everything you need, including all templates, translation files, et cetera.
+## Popular Use Cases
+
+### Build Once – Use Across Jobs
+
+To increase the fidelity of your tests to what your users will experience, you can build and store your package as a first step, depend on the step in the remaining steps, and – instead of checking out the source tree – retrieve the built packages and run your tests against *that*.
+For example, by unpacking the tests and config from the SDist and using `tox run --installpkg dist/*.whl ...` to run the tests against the built wheel without access to the package source code.
+
+You can see this technique in action in [*structlog*’s CI](https://github.com/hynek/structlog/blob/main/.github/workflows/ci.yml).
+
+
+### Automatic Uploading
+
+You can use a workflow that builds your package and – depending on the CI event (push to main, new tag, new release, ...) – uses [PyPI’s trusted publisher feature](https://blog.pypi.org/posts/2023-04-20-introducing-trusted-publishers/) to upload it to [Test PyPI](https://test.pypi.org)[^unique], PyPI, or both.
+This way you can continuously check how the package will look on PyPI.
+
+*structlog* [uses](https://github.com/hynek/structlog/blob/main/.github/workflows/pypi-package.yml) this technique too:
+It uploads every commit on `main` to [Test PyPI](https://test.pypi.org/project/structlog/#history) and whenever a [GitHub Release](https://github.com/hynek/structlog/releases) is created, also to the real PyPI.
+
+[^unique]: Note, though, that a prerequisite for the Test PyPI workflow is that each of your commits builds with a unique version number.
+ This is easily achievable using tools like [*setuptools-scm*](https://setuptools-scm.readthedocs.io/) or [*hatch-vcs*](https://github.com/ofek/hatch-vcs), but beyond the scope of this humble README.
+
+
+### Define Python Version Matrix Based On Package Metadata
+
+*build-and-inspect-python-package* extracts the Python versions your package supports from the trove classifiers in your package’s metadata and offers them as an action output.
+
+That means that you can define your CI matrix based on the Python versions your package supports without duplicating the information between your package configuration and your CI configuration.
+
+
+### Applications
+
+If you package an **application** as a Python package, this action is useful to double-check you’re shipping everything you need, including all templates, translation files, et cetera.
## Usage
+*build-and-inspect-python-package* only works on Linux runners:
+
```yaml
jobs:
- check-package:
- name: Build & inspect our package.
+ build-and-inspect-package:
+ name: Build & inspect package.
runs-on: ubuntu-latest
steps:
- - uses: actions/checkout@v3
- - uses: hynek/build-and-inspect-python-package@v1
+ - uses: actions/checkout@v4
+ - uses: hynek/build-and-inspect-python-package@v2
```
+To also upload to PyPI:
+
+```yaml
+jobs:
+ build-and-inspect-package:
+ name: Build & inspect package.
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v4
+ - uses: hynek/build-and-inspect-python-package@v2
+
+
+ upload-to-pypi:
+ name: Upload package to PyPI
+ needs: build-and-inspect-package
+ runs-on: ubuntu-latest
+ permissions:
+ # IMPORTANT: this permission is mandatory for trusted publishing, but
+ # should NOT be granted anywhere else!
+ id-token: write
+
+ steps:
+ - name: Download built artifact to dist/
+ uses: actions/download-artifact@v4
+ with:
+ name: Packages
+ path: dist
+ - uses: pypa/gh-action-pypi-publish@release/v1
+```
+
+> [!IMPORTANT]
+> For security reasons, keep the job that has the `id-token: write` permission as short as possible.
+
+---
+
+If you’re using a VCS tag-based version extractor like [*setuptools-scm*] and need the built package to have the correct version, you must use *actions/checkout* with `fetch-depth: 0` – unless the latest commit _is_ the version tag.
+
+> [!CAUTION]
+> *build-and-inspect-python-package* uses [*actions/upload-artifact*](https://github.com/actions/upload-artifact) for storing the built artifacts that you can download with [*actions/download-artifact*](https://github.com/actions/download-artifact).
+>
+> Unfortunately, v4 of both [is incompatible](https://github.blog/changelog/2023-12-14-github-actions-artifacts-v4-is-now-generally-available/) with previous versions, so you have to make sure that your *download-artifact* version matches the version that *build-and-inspect-python-package* uses for uploading.
+>
+> - If you’re using `download-artifact@v3`, you have to use `build-and-inspect-python-package@v1`.
+> - If you’re using `download-artifact@v4`, you have to use `build-and-inspect-python-package@v2`.
+
+While *build-and-inspect-python-package* will build a wheel for you by default, we recommend using [*cibuildwheel*] if your package contains compiled extensions.
+
### Inputs
- `path`: the location of the Python package to build (*optional*, default: `.`).
+- `skip-wheel`: Whether to skip building the wheel in addition to the source distribution.
+ The only meaningful value is `'true'` (note the quotes – GitHub Actions only allow string inputs) and everything else is treated as falsey.
+
+ This is useful if you build your wheels using advanced tools like [*cibuildwheel*] anyway.
+ (*optional*, default: `'false'`).
+- `upload-name-suffix`: A suffix to append to the artifact names to make them unique for `upload-artifact@v4`.
+
+ Use this if you want to build multiple packages in one workflow.
+ (*optional*, default: `''`).
+- `attest-build-provenance-github`: Whether to generate signed build provenance attestations for workflow artifacts using [actions/attest-build-provenance](https://github.com/actions/attest-build-provenance).
+ Requires `attestations: write` and `id-token: write` permissions.
+ The only meaningful value is `'true'` (note the quotes – GitHub Actions only allow string inputs) and everything else is treated as falsey.
+ (*optional*, default: `'false'`).
+
+> [!IMPORTANT]
+> [GitHub's artifact attestations](https://docs.github.com/en/actions/security-for-github-actions/using-artifact-attestations/using-artifact-attestations-to-establish-provenance-for-builds) are different from PyPI's [Sigstore](https://www.sigstore.dev) attestations that you can generate while uploading using [*pypa/gh-action-pypi-publish*](https://github.com/pypa/gh-action-pypi-publish?tab=readme-ov-file#generating-and-uploading-attestations).
### Outputs
-- `dist`: the location with the built packages.
+- `artifact-name`: The name of the uploaded artifact.
+
+- `dist`: The location with the built packages.
+
+ See, for example, how [*argon2-cffi-bindings*](https://github.com/hynek/argon2-cffi-bindings/blob/daff9ceb693312ab8257c60db4cd1c13cd866a35/.github/workflows/ci.yml#L83-L97) uses this feature to check the built wheels don’t break a package that depends on it.
- See for example how [*argon2-cffi-bindings*](https://github.com/hynek/argon2-cffi-bindings/blob/a9d295e577b271b1c7f6ca3929fe8b39ba8b689e/.github/workflows/ci.yml#L75-L85) uses this feature to check the built wheels don't break a dependency.
+- `supported_python_classifiers_json_array`: A JSON array of Python versions that are supported by the package as defined by the trove classifiers in the package metadata (for example, `Programming Language :: Python :: 3.12`).
+ You can assign this to a matrix strategy key in your CI job (for example, `strategy.matrix.python-version`) to test against multiple Python versions without duplicating the information.
+ Since GitHub Actions only allows for strings as variables, you have to parse it with `fromJSON` in your workflow.
+
+ If all this sounds confusing: Check out our [supported Pythons CI workflow] for a realistic example.
+
+- `supported_python_classifiers_json_job_matrix_value`: Same as `supported_python_classifiers_json_array`, but it’s a mapping with the JSON array bound to the `python-version` key.
+
+ This is useful if you only want to define a matrix based on Python versions, because then you can just assign this to `strategy.matrix`.
+
+- `package_version`: The version of the package as extracted from the package metadata.
+
+ This is useful, for example, for displaying the PyPI URL on the GitHub UI for the publishing job:
+
+ ```yaml
+ jobs:
+ ...
+ release:
+ runs-on: ubuntu-latest
+ needs: baipp
+ environment:
+ name: pypi
+ url: https://pypi.org/project/structlog/${{ needs.baipp.outputs.package-version }}
+ ```
### Artifacts
-After a successful run, you'll find multiple artifacts in the run's Summary view:
+After a successful run, you’ll find the following artifacts in the run’s Summary view:
- **Packages**: The built packages.
Perfect for [automated PyPI upload workflows][automated]!
-- **Package Metadata**: the extracted packaging metadata (*hint*: it's formatted as an email).
-- **PyPI README**: the extracted PyPI README, exactly how it would be used by PyPI as your project's landing page.
- [PEP 621](https://peps.python.org/pep-0621/) calls it `readme`, in classic *setuptools* it's `long_description`.
+- **Package Metadata**: the extracted packaging metadata (*hint*: it’s formatted as an email).
+- **PyPI README**: the extracted PyPI README, exactly how it would be used by PyPI as your project’s landing page.
+ [PEP 621](https://peps.python.org/pep-0621/) calls it `readme`, in classic *setuptools* it’s `long_description`.
----
+
+### Job Summaries
+
+To save you from downloading the artifacts just to check their contents, *build-and-inspect-python-package* creates the following job summaries:
+
+- **SDist contents**: A tree of the source distribution.
+- **Wheel contents**: A tree of the built wheel – if one was built.
+ This output has no timestamps because `wheel unpack` does not preserve them from the built wheel, leading to confusion.
+- **Metadata**: A plain-text dump of package metadata (includes the PyPI README).
+
+
+### Examples
[Our CI](.github/workflows/ci.yml) uses all inputs and outputs, if you want to see them in action.
+Our [supported Pythons CI workflow] demonstrates how to use `supported_python_classifiers_json_array` to set up a matrix of Python versions for your CI jobs without duplicating the information with your packaging metadata.
+
## License
The scripts and documentation in this project are released under the [MIT License](LICENSE).
[automated]: https://github.com/python-attrs/attrs/blob/main/.github/workflows/pypi-package.yml
+[*cibuildwheel*]: https://cibuildwheel.pypa.io/
+[*setuptools-scm*]: https://setuptools-scm.readthedocs.io/
+[supported Pythons CI workflow]: .github/workflows/ci-supported-pythons.yml
diff --git a/action.yml b/action.yml
index 33af5ef..3810915 100644
--- a/action.yml
+++ b/action.yml
@@ -11,38 +11,139 @@ inputs:
description: Where to look for the Python package to inspect.
required: false
default: .
+ skip-wheel:
+ description: Only build the source distribution.
+ required: false
+ default: 'false'
+ upload-name-suffix:
+ description: Suffix to append to the artifact names.
+ required: false
+ default: ""
+ attest-build-provenance-github:
+ description: "Attest provenance using GitHub's own action. Requires 'attestations: write' and 'id-token: write' permissions."
+ required: false
+ default: 'false'
outputs:
+ artifact-name:
+ description: The name of the uploaded artifact.
+ value: ${{ steps.artifact.outputs.name }}
dist:
description: The location of the built packages.
- value: ${{ steps.setter.outputs.dist }}
+ value: ${{ steps.dist-location-setter.outputs.dist }}
+ supported_python_classifiers_json_array:
+ description: >
+ A JSON array that contains all classifier-declared supported Python
+ versions. When loaded using the 'fromJson' function, this can be assigned
+ to a matrix strategy key (for example, `python-version`).
+
+ value: ${{ steps.metadata-setter.outputs.supported_python_classifiers_json_array }}
+ supported_python_classifiers_json_job_matrix_value:
+ description: >
+ Same as 'supported_python_classifiers_json_array', except it's already a
+ JSON mapping from "python-version" to a list of all classifier-declared
+ supported Python versions. In other words, you can assign it directly to
+ the 'strategy.matrix' key.
+ value: ${{ steps.metadata-setter.outputs.supported_python_classifiers_json_job_matrix_value }}
+ package_version:
+ description: The version of the package as declared in the metadata.
+ value: ${{ steps.metadata-setter.outputs.package_version }}
runs:
using: composite
+
steps:
- - uses: actions/setup-python@v4
+ - uses: actions/setup-python@v5
id: python-baipp
with:
python-version: "3.x"
update-environment: false
+ - name: Install uv
+ run: >
+ curl
+ --location
+ --silent
+ --show-error
+ --fail
+ --proto '=https'
+ --tlsv1.2
+ https://astral.sh/uv/install.sh | bash
+ shell: bash
+
+ - name: Set uv cache and hash lock file
+ run: |
+ echo "UV_CACHE_DIR=/tmp/baipp-uv_cache_dir" >>$GITHUB_ENV
+
+ echo "REQS_HASH=$(sha256sum ${{ github.action_path }}/requirements/tools.txt | cut -d' ' -f1)" >>$GITHUB_ENV
+ shell: bash
+
+ - name: Setup uv cache
+ uses: actions/cache@v4
+ with:
+ path: ${{ env.UV_CACHE_DIR }}
+ key: baipp-${{ env.REQS_HASH }}
+
- name: Create venv for tools
- run: ${{ steps.python-baipp.outputs.python-path }} -Im venv /tmp/baipp
+ run: |
+ unset UV_SYSTEM_PYTHON
+
+ uv venv \
+ /tmp/baipp \
+ --python ${{ steps.python-baipp.outputs.python-path }}
shell: bash
- - run: /tmp/baipp/bin/python -Im pip install -r ${{ github.action_path }}/requirements/tools.txt
+ - name: Install our tools
+ run: |
+ unset UV_SYSTEM_PYTHON
+
+ uv pip sync \
+ ${{ github.action_path }}/requirements/tools.txt
shell: bash
+ env:
+ VIRTUAL_ENV: /tmp/baipp
- # Build SDist, then build wheel out of it.
- - run: |
- # Set 'SOURCE_DATE_EPOCH' based on the last commit for build
- # reproducibility.
- SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct) \
- /tmp/baipp/bin/python -m build --outdir /tmp/baipp/dist
+ - name: Artifact Name
+ id: artifact
+ run: echo "name=Packages${{ inputs.upload-name-suffix }}" >>${GITHUB_OUTPUT}
+ shell: bash
+
+ # Build SDist, then build wheel out of it if the user didn't forbid it.
+ # Set 'SOURCE_DATE_EPOCH' based on the last commit for build
+ # reproducibility.
+ - name: Build package
+ run: |
+ unset UV_SYSTEM_PYTHON
+
+ echo Setting SOURCE_DATE_EPOCH to $(git log -1 --pretty=%ct).
+ export SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
+
+ if [[ "${{ inputs.skip-wheel }}" == "true" ]]; then
+ uv build --sdist --out-dir /tmp/baipp/dist
+ else
+ uv build --out-dir /tmp/baipp/dist
+ fi
+
+ # We don't need .gitignores and it litters the provenance output.
+ rm -f /tmp/baipp/dist/.gitignore
shell: bash
working-directory: ${{ inputs.path }}
+ - name: Optimize uv cache for CI
+ run: uv cache prune --ci
+ shell: bash
+
+ - name: Attest GitHub build provenance
+ if: ${{ inputs.attest-build-provenance-github == 'true' }}
+ uses: actions/attest-build-provenance@v1
+ with:
+ subject-path: "/tmp/baipp/dist/*"
+
+ - name: Add contents header
+ shell: bash
+ run: echo -e '\n### Package Contents' >> $GITHUB_STEP_SUMMARY
+
- name: Set output
- id: setter
+ id: dist-location-setter
shell: bash
run: echo "dist=/tmp/baipp/dist" >>$GITHUB_OUTPUT
@@ -52,37 +153,52 @@ runs:
working-directory: ${{ inputs.path }}
- name: Upload built artifacts.
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: Packages
+ name: ${{ steps.artifact.outputs.name }}
path: /tmp/baipp/dist/*
- - run: /tmp/baipp/bin/check-wheel-contents /tmp/baipp/dist/*.whl
+ - name: Check wheel contents if one was built
+ run: |
+ if [[ "${{ inputs.skip-wheel }}" != 'true' ]]; then
+ /tmp/baipp/bin/check-wheel-contents /tmp/baipp/dist/*.whl
+ fi
shell: bash
working-directory: ${{ inputs.path }}
- name: Check PyPI README
shell: bash
working-directory: ${{ inputs.path }}
- run: /tmp/baipp/bin/python -m twine check --strict /tmp/baipp/dist/*
+ run: >
+ /tmp/baipp/bin/python
+ -m twine check
+ --strict
+ /tmp/baipp/dist/*
- - name: Show wheel & SDist contents hierarchically, including metadata.
+ - name: Show package contents hierarchically, including metadata.
shell: bash
working-directory: ${{ inputs.path }}
run: |
cd /tmp/baipp/dist
mkdir -p out/sdist
- mkdir -p out/wheels
- /tmp/baipp/bin/python -m wheel unpack --dest out/wheels *.whl
tar xf *.tar.gz -C out/sdist
+ if ! command -v tree &> /dev/null; then
+ sudo apt-get install tree
+ fi
+
echo -e '\nSDist contents
\n' >> $GITHUB_STEP_SUMMARY
(cd /tmp/baipp/dist/out/sdist && tree -Da --timefmt="%Y-%m-%dT%H:%M:%SZ" * | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY)
echo -e '\n \n' >> $GITHUB_STEP_SUMMARY
- echo -e '\nWheel contents
\n' >> $GITHUB_STEP_SUMMARY
- (cd /tmp/baipp/dist/out/wheels && tree -Da --timefmt="%Y-%m-%dT%H:%M:%SZ" * | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY)
- echo -e '\n \n' >> $GITHUB_STEP_SUMMARY
+ if [[ "${{ inputs.skip-wheel }}" != 'true' ]]; then
+ mkdir -p out/wheels
+ /tmp/baipp/bin/python -m wheel unpack --dest out/wheels *.whl
+
+ echo -e '\nWheel contents
\n' >> $GITHUB_STEP_SUMMARY
+ (cd /tmp/baipp/dist/out/wheels && tree -a * | sed 's/^/ /' | tee -a $GITHUB_STEP_SUMMARY)
+ echo -e '\n \n' >> $GITHUB_STEP_SUMMARY
+ fi
echo ----- Metadata Follows -----
echo -e '\nMetadata
\n' >> $GITHUB_STEP_SUMMARY
@@ -91,9 +207,9 @@ runs:
echo ----- End of Metadata -----
- name: Upload metadata
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: Package Metadata
+ name: Package Metadata${{ inputs.upload-name-suffix }}
path: /tmp/baipp/dist/out/sdist/*/PKG-INFO
- name: Extract PyPI README
@@ -114,7 +230,30 @@ runs:
'
- name: Upload PyPI README
- uses: actions/upload-artifact@v3
+ uses: actions/upload-artifact@v4
with:
- name: PyPI README
+ name: PyPI README${{ inputs.upload-name-suffix }}
path: /tmp/baipp/dist/out/sdist/PyPI-README.*
+
+ - name: Generate JSON objects of supported Python versions
+ id: metadata-setter
+ shell: bash
+ working-directory: /tmp/baipp/dist/out/sdist/
+ run: |
+ cat */PKG-INFO | python -c '
+ import email.parser
+ import json, re, sys
+
+ pkg_info = email.parser.Parser().parsestr(sys.stdin.read())
+
+ version_tokens = []
+ for classifier in pkg_info.get_all("Classifier", []):
+ if match := re.match(r"Programming Language :: Python :: (\d+\.\d+)$", classifier):
+ version_tokens.append(match.group(1))
+
+ package_version = pkg_info.get("Version", "0.0.0")
+
+ print(f"package_version={package_version}")
+ print(f"supported_python_classifiers_json_array={json.dumps(version_tokens)}")
+ print(f"""supported_python_classifiers_json_job_matrix_value={json.dumps({"python-version": version_tokens})}""")
+ ' >> $GITHUB_OUTPUT
diff --git a/requirements/pip-tools.in b/requirements/pip-tools.in
deleted file mode 100644
index e89961a..0000000
--- a/requirements/pip-tools.in
+++ /dev/null
@@ -1,2 +0,0 @@
-pip-tools
-wheel
diff --git a/requirements/pip-tools.txt b/requirements/pip-tools.txt
deleted file mode 100644
index ef7f4bf..0000000
--- a/requirements/pip-tools.txt
+++ /dev/null
@@ -1,26 +0,0 @@
-#
-# This file is autogenerated by pip-compile with python 3.10
-# To update, run:
-#
-# pip-compile --output-file=requirements/pip-tools.txt requirements/pip-tools.in
-#
-build==0.8.0
- # via pip-tools
-click==8.1.3
- # via pip-tools
-packaging==21.3
- # via build
-pep517==0.13.0
- # via build
-pip-tools==6.8.0
- # via -r pip-tools.in
-pyparsing==3.0.9
- # via packaging
-wheel==0.38.1
- # via
- # -r pip-tools.in
- # pip-tools
-
-# The following packages are considered to be unsafe in a requirements file:
-# pip
-# setuptools
diff --git a/requirements/tools.in b/requirements/tools.in
index 72e5067..28bf533 100644
--- a/requirements/tools.in
+++ b/requirements/tools.in
@@ -1,4 +1,3 @@
-build
check-wheel-contents
twine
wheel
diff --git a/requirements/tools.txt b/requirements/tools.txt
index d356b2e..23fc916 100644
--- a/requirements/tools.txt
+++ b/requirements/tools.txt
@@ -1,99 +1,461 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-# pip-compile --output-file=requirements/tools.txt requirements/tools.in
-#
-attrs==22.2.0
+# This file was autogenerated by uv via the following command:
+# uv pip compile --generate-hashes --output-file=requirements/tools.txt requirements/tools.in
+annotated-types==0.7.0 \
+ --hash=sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53 \
+ --hash=sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89
+ # via pydantic
+attrs==24.3.0 \
+ --hash=sha256:8f5c07333d543103541ba7be0e2ce16eeee8130cb0b3f9238ab904ce1e85baff \
+ --hash=sha256:ac96cd038792094f438ad1f6ff80837353805ac950cd2aa0e0625ef19850c308
# via check-wheel-contents
-bleach==6.0.0
- # via readme-renderer
-build==0.10.0
- # via -r requirements/tools.in
-certifi==2022.12.7
+certifi==2024.12.14 \
+ --hash=sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56 \
+ --hash=sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db
# via requests
-cffi==1.15.1
+cffi==1.17.1 \
+ --hash=sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8 \
+ --hash=sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2 \
+ --hash=sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1 \
+ --hash=sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15 \
+ --hash=sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36 \
+ --hash=sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824 \
+ --hash=sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8 \
+ --hash=sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36 \
+ --hash=sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17 \
+ --hash=sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf \
+ --hash=sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc \
+ --hash=sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3 \
+ --hash=sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed \
+ --hash=sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702 \
+ --hash=sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1 \
+ --hash=sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8 \
+ --hash=sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903 \
+ --hash=sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6 \
+ --hash=sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d \
+ --hash=sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b \
+ --hash=sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e \
+ --hash=sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be \
+ --hash=sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c \
+ --hash=sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683 \
+ --hash=sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9 \
+ --hash=sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c \
+ --hash=sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8 \
+ --hash=sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1 \
+ --hash=sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4 \
+ --hash=sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655 \
+ --hash=sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67 \
+ --hash=sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595 \
+ --hash=sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0 \
+ --hash=sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65 \
+ --hash=sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41 \
+ --hash=sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6 \
+ --hash=sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401 \
+ --hash=sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6 \
+ --hash=sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3 \
+ --hash=sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16 \
+ --hash=sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93 \
+ --hash=sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e \
+ --hash=sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4 \
+ --hash=sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964 \
+ --hash=sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c \
+ --hash=sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576 \
+ --hash=sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0 \
+ --hash=sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3 \
+ --hash=sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662 \
+ --hash=sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3 \
+ --hash=sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff \
+ --hash=sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5 \
+ --hash=sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd \
+ --hash=sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f \
+ --hash=sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5 \
+ --hash=sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14 \
+ --hash=sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d \
+ --hash=sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9 \
+ --hash=sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7 \
+ --hash=sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382 \
+ --hash=sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a \
+ --hash=sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e \
+ --hash=sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a \
+ --hash=sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4 \
+ --hash=sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99 \
+ --hash=sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87 \
+ --hash=sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b
# via cryptography
-charset-normalizer==3.0.1
+charset-normalizer==3.4.1 \
+ --hash=sha256:0167ddc8ab6508fe81860a57dd472b2ef4060e8d378f0cc555707126830f2537 \
+ --hash=sha256:01732659ba9b5b873fc117534143e4feefecf3b2078b0a6a2e925271bb6f4cfa \
+ --hash=sha256:01ad647cdd609225c5350561d084b42ddf732f4eeefe6e678765636791e78b9a \
+ --hash=sha256:04432ad9479fa40ec0f387795ddad4437a2b50417c69fa275e212933519ff294 \
+ --hash=sha256:0907f11d019260cdc3f94fbdb23ff9125f6b5d1039b76003b5b0ac9d6a6c9d5b \
+ --hash=sha256:0924e81d3d5e70f8126529951dac65c1010cdf117bb75eb02dd12339b57749dd \
+ --hash=sha256:09b26ae6b1abf0d27570633b2b078a2a20419c99d66fb2823173d73f188ce601 \
+ --hash=sha256:09b5e6733cbd160dcc09589227187e242a30a49ca5cefa5a7edd3f9d19ed53fd \
+ --hash=sha256:0af291f4fe114be0280cdd29d533696a77b5b49cfde5467176ecab32353395c4 \
+ --hash=sha256:0f55e69f030f7163dffe9fd0752b32f070566451afe180f99dbeeb81f511ad8d \
+ --hash=sha256:1a2bc9f351a75ef49d664206d51f8e5ede9da246602dc2d2726837620ea034b2 \
+ --hash=sha256:22e14b5d70560b8dd51ec22863f370d1e595ac3d024cb8ad7d308b4cd95f8313 \
+ --hash=sha256:234ac59ea147c59ee4da87a0c0f098e9c8d169f4dc2a159ef720f1a61bbe27cd \
+ --hash=sha256:2369eea1ee4a7610a860d88f268eb39b95cb588acd7235e02fd5a5601773d4fa \
+ --hash=sha256:237bdbe6159cff53b4f24f397d43c6336c6b0b42affbe857970cefbb620911c8 \
+ --hash=sha256:28bf57629c75e810b6ae989f03c0828d64d6b26a5e205535585f96093e405ed1 \
+ --hash=sha256:2967f74ad52c3b98de4c3b32e1a44e32975e008a9cd2a8cc8966d6a5218c5cb2 \
+ --hash=sha256:2a75d49014d118e4198bcee5ee0a6f25856b29b12dbf7cd012791f8a6cc5c496 \
+ --hash=sha256:2bdfe3ac2e1bbe5b59a1a63721eb3b95fc9b6817ae4a46debbb4e11f6232428d \
+ --hash=sha256:2d074908e1aecee37a7635990b2c6d504cd4766c7bc9fc86d63f9c09af3fa11b \
+ --hash=sha256:2fb9bd477fdea8684f78791a6de97a953c51831ee2981f8e4f583ff3b9d9687e \
+ --hash=sha256:311f30128d7d333eebd7896965bfcfbd0065f1716ec92bd5638d7748eb6f936a \
+ --hash=sha256:329ce159e82018d646c7ac45b01a430369d526569ec08516081727a20e9e4af4 \
+ --hash=sha256:345b0426edd4e18138d6528aed636de7a9ed169b4aaf9d61a8c19e39d26838ca \
+ --hash=sha256:363e2f92b0f0174b2f8238240a1a30142e3db7b957a5dd5689b0e75fb717cc78 \
+ --hash=sha256:3a3bd0dcd373514dcec91c411ddb9632c0d7d92aed7093b8c3bbb6d69ca74408 \
+ --hash=sha256:3bed14e9c89dcb10e8f3a29f9ccac4955aebe93c71ae803af79265c9ca5644c5 \
+ --hash=sha256:44251f18cd68a75b56585dd00dae26183e102cd5e0f9f1466e6df5da2ed64ea3 \
+ --hash=sha256:44ecbf16649486d4aebafeaa7ec4c9fed8b88101f4dd612dcaf65d5e815f837f \
+ --hash=sha256:4532bff1b8421fd0a320463030c7520f56a79c9024a4e88f01c537316019005a \
+ --hash=sha256:49402233c892a461407c512a19435d1ce275543138294f7ef013f0b63d5d3765 \
+ --hash=sha256:4c0907b1928a36d5a998d72d64d8eaa7244989f7aaaf947500d3a800c83a3fd6 \
+ --hash=sha256:4d86f7aff21ee58f26dcf5ae81a9addbd914115cdebcbb2217e4f0ed8982e146 \
+ --hash=sha256:5777ee0881f9499ed0f71cc82cf873d9a0ca8af166dfa0af8ec4e675b7df48e6 \
+ --hash=sha256:5df196eb874dae23dcfb968c83d4f8fdccb333330fe1fc278ac5ceeb101003a9 \
+ --hash=sha256:619a609aa74ae43d90ed2e89bdd784765de0a25ca761b93e196d938b8fd1dbbd \
+ --hash=sha256:6e27f48bcd0957c6d4cb9d6fa6b61d192d0b13d5ef563e5f2ae35feafc0d179c \
+ --hash=sha256:6ff8a4a60c227ad87030d76e99cd1698345d4491638dfa6673027c48b3cd395f \
+ --hash=sha256:73d94b58ec7fecbc7366247d3b0b10a21681004153238750bb67bd9012414545 \
+ --hash=sha256:7461baadb4dc00fd9e0acbe254e3d7d2112e7f92ced2adc96e54ef6501c5f176 \
+ --hash=sha256:75832c08354f595c760a804588b9357d34ec00ba1c940c15e31e96d902093770 \
+ --hash=sha256:7709f51f5f7c853f0fb938bcd3bc59cdfdc5203635ffd18bf354f6967ea0f824 \
+ --hash=sha256:78baa6d91634dfb69ec52a463534bc0df05dbd546209b79a3880a34487f4b84f \
+ --hash=sha256:7974a0b5ecd505609e3b19742b60cee7aa2aa2fb3151bc917e6e2646d7667dcf \
+ --hash=sha256:7a4f97a081603d2050bfaffdefa5b02a9ec823f8348a572e39032caa8404a487 \
+ --hash=sha256:7b1bef6280950ee6c177b326508f86cad7ad4dff12454483b51d8b7d673a2c5d \
+ --hash=sha256:7d053096f67cd1241601111b698f5cad775f97ab25d81567d3f59219b5f1adbd \
+ --hash=sha256:804a4d582ba6e5b747c625bf1255e6b1507465494a40a2130978bda7b932c90b \
+ --hash=sha256:807f52c1f798eef6cf26beb819eeb8819b1622ddfeef9d0977a8502d4db6d534 \
+ --hash=sha256:80ed5e856eb7f30115aaf94e4a08114ccc8813e6ed1b5efa74f9f82e8509858f \
+ --hash=sha256:8417cb1f36cc0bc7eaba8ccb0e04d55f0ee52df06df3ad55259b9a323555fc8b \
+ --hash=sha256:8436c508b408b82d87dc5f62496973a1805cd46727c34440b0d29d8a2f50a6c9 \
+ --hash=sha256:89149166622f4db9b4b6a449256291dc87a99ee53151c74cbd82a53c8c2f6ccd \
+ --hash=sha256:8bfa33f4f2672964266e940dd22a195989ba31669bd84629f05fab3ef4e2d125 \
+ --hash=sha256:8c60ca7339acd497a55b0ea5d506b2a2612afb2826560416f6894e8b5770d4a9 \
+ --hash=sha256:91b36a978b5ae0ee86c394f5a54d6ef44db1de0815eb43de826d41d21e4af3de \
+ --hash=sha256:955f8851919303c92343d2f66165294848d57e9bba6cf6e3625485a70a038d11 \
+ --hash=sha256:97f68b8d6831127e4787ad15e6757232e14e12060bec17091b85eb1486b91d8d \
+ --hash=sha256:9b23ca7ef998bc739bf6ffc077c2116917eabcc901f88da1b9856b210ef63f35 \
+ --hash=sha256:9f0b8b1c6d84c8034a44893aba5e767bf9c7a211e313a9605d9c617d7083829f \
+ --hash=sha256:aabfa34badd18f1da5ec1bc2715cadc8dca465868a4e73a0173466b688f29dda \
+ --hash=sha256:ab36c8eb7e454e34e60eb55ca5d241a5d18b2c6244f6827a30e451c42410b5f7 \
+ --hash=sha256:b010a7a4fd316c3c484d482922d13044979e78d1861f0e0650423144c616a46a \
+ --hash=sha256:b1ac5992a838106edb89654e0aebfc24f5848ae2547d22c2c3f66454daa11971 \
+ --hash=sha256:b7b2d86dd06bfc2ade3312a83a5c364c7ec2e3498f8734282c6c3d4b07b346b8 \
+ --hash=sha256:b97e690a2118911e39b4042088092771b4ae3fc3aa86518f84b8cf6888dbdb41 \
+ --hash=sha256:bc2722592d8998c870fa4e290c2eec2c1569b87fe58618e67d38b4665dfa680d \
+ --hash=sha256:c0429126cf75e16c4f0ad00ee0eae4242dc652290f940152ca8c75c3a4b6ee8f \
+ --hash=sha256:c30197aa96e8eed02200a83fba2657b4c3acd0f0aa4bdc9f6c1af8e8962e0757 \
+ --hash=sha256:c4c3e6da02df6fa1410a7680bd3f63d4f710232d3139089536310d027950696a \
+ --hash=sha256:c75cb2a3e389853835e84a2d8fb2b81a10645b503eca9bcb98df6b5a43eb8886 \
+ --hash=sha256:c96836c97b1238e9c9e3fe90844c947d5afbf4f4c92762679acfe19927d81d77 \
+ --hash=sha256:d7f50a1f8c450f3925cb367d011448c39239bb3eb4117c36a6d354794de4ce76 \
+ --hash=sha256:d973f03c0cb71c5ed99037b870f2be986c3c05e63622c017ea9816881d2dd247 \
+ --hash=sha256:d98b1668f06378c6dbefec3b92299716b931cd4e6061f3c875a71ced1780ab85 \
+ --hash=sha256:d9c3cdf5390dcd29aa8056d13e8e99526cda0305acc038b96b30352aff5ff2bb \
+ --hash=sha256:dad3e487649f498dd991eeb901125411559b22e8d7ab25d3aeb1af367df5efd7 \
+ --hash=sha256:dccbe65bd2f7f7ec22c4ff99ed56faa1e9f785482b9bbd7c717e26fd723a1d1e \
+ --hash=sha256:dd78cfcda14a1ef52584dbb008f7ac81c1328c0f58184bf9a84c49c605002da6 \
+ --hash=sha256:e218488cd232553829be0664c2292d3af2eeeb94b32bea483cf79ac6a694e037 \
+ --hash=sha256:e358e64305fe12299a08e08978f51fc21fac060dcfcddd95453eabe5b93ed0e1 \
+ --hash=sha256:ea0d8d539afa5eb2728aa1932a988a9a7af94f18582ffae4bc10b3fbdad0626e \
+ --hash=sha256:eab677309cdb30d047996b36d34caeda1dc91149e4fdca0b1a039b3f79d9a807 \
+ --hash=sha256:eb8178fe3dba6450a3e024e95ac49ed3400e506fd4e9e5c32d30adda88cbd407 \
+ --hash=sha256:ecddf25bee22fe4fe3737a399d0d177d72bc22be6913acfab364b40bce1ba83c \
+ --hash=sha256:eea6ee1db730b3483adf394ea72f808b6e18cf3cb6454b4d86e04fa8c4327a12 \
+ --hash=sha256:f08ff5e948271dc7e18a35641d2f11a4cd8dfd5634f55228b691e62b37125eb3 \
+ --hash=sha256:f30bf9fd9be89ecb2360c7d94a711f00c09b976258846efe40db3d05828e8089 \
+ --hash=sha256:fa88b843d6e211393a37219e6a1c1df99d35e8fd90446f1118f4216e307e48cd \
+ --hash=sha256:fc54db6c8593ef7d4b2a331b58653356cf04f67c960f584edb7c3d8c97e8f39e \
+ --hash=sha256:fd4ec41f914fa74ad1b8304bbc634b3de73d2a0889bd32076342a573e0779e00 \
+ --hash=sha256:ffc9202a29ab3920fa812879e95a9e78b2465fd10be7fcbd042899695d75e616
# via requests
-check-wheel-contents==0.4.0
+check-wheel-contents==0.6.1 \
+ --hash=sha256:38ccb184c89c6d378d3daba4f0edae49394fb4e6c2f082a8dbcae4f653007ec6 \
+ --hash=sha256:d1261166c24a7a0f202016e38f2601452580674e9bb35667530c2b1a1c36f690
# via -r requirements/tools.in
-click==8.1.3
+click==8.1.8 \
+ --hash=sha256:63c132bbbed01578a06712a2d1f497bb62d9c1c0d329b7903a866228027263b2 \
+ --hash=sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a
# via check-wheel-contents
-cryptography==39.0.1
+cryptography==44.0.0 \
+ --hash=sha256:1923cb251c04be85eec9fda837661c67c1049063305d6be5721643c22dd4e2b7 \
+ --hash=sha256:37d76e6863da3774cd9db5b409a9ecfd2c71c981c38788d3fcfaf177f447b731 \
+ --hash=sha256:3c672a53c0fb4725a29c303be906d3c1fa99c32f58abe008a82705f9ee96f40b \
+ --hash=sha256:404fdc66ee5f83a1388be54300ae978b2efd538018de18556dde92575e05defc \
+ --hash=sha256:4ac4c9f37eba52cb6fbeaf5b59c152ea976726b865bd4cf87883a7e7006cc543 \
+ --hash=sha256:62901fb618f74d7d81bf408c8719e9ec14d863086efe4185afd07c352aee1d2c \
+ --hash=sha256:660cb7312a08bc38be15b696462fa7cc7cd85c3ed9c576e81f4dc4d8b2b31591 \
+ --hash=sha256:708ee5f1bafe76d041b53a4f95eb28cdeb8d18da17e597d46d7833ee59b97ede \
+ --hash=sha256:761817a3377ef15ac23cd7834715081791d4ec77f9297ee694ca1ee9c2c7e5eb \
+ --hash=sha256:831c3c4d0774e488fdc83a1923b49b9957d33287de923d58ebd3cec47a0ae43f \
+ --hash=sha256:84111ad4ff3f6253820e6d3e58be2cc2a00adb29335d4cacb5ab4d4d34f2a123 \
+ --hash=sha256:8b3e6eae66cf54701ee7d9c83c30ac0a1e3fa17be486033000f2a73a12ab507c \
+ --hash=sha256:9e6fc8a08e116fb7c7dd1f040074c9d7b51d74a8ea40d4df2fc7aa08b76b9e6c \
+ --hash=sha256:a01956ddfa0a6790d594f5b34fc1bfa6098aca434696a03cfdbe469b8ed79285 \
+ --hash=sha256:abc998e0c0eee3c8a1904221d3f67dcfa76422b23620173e28c11d3e626c21bd \
+ --hash=sha256:b15492a11f9e1b62ba9d73c210e2416724633167de94607ec6069ef724fad092 \
+ --hash=sha256:be4ce505894d15d5c5037167ffb7f0ae90b7be6f2a98f9a5c3442395501c32fa \
+ --hash=sha256:c5eb858beed7835e5ad1faba59e865109f3e52b3783b9ac21e7e47dc5554e289 \
+ --hash=sha256:cd4e834f340b4293430701e772ec543b0fbe6c2dea510a5286fe0acabe153a02 \
+ --hash=sha256:d2436114e46b36d00f8b72ff57e598978b37399d2786fd39793c36c6d5cb1c64 \
+ --hash=sha256:eb33480f1bad5b78233b0ad3e1b0be21e8ef1da745d8d2aecbb20671658b9053 \
+ --hash=sha256:eca27345e1214d1b9f9490d200f9db5a874479be914199194e746c893788d417 \
+ --hash=sha256:ed3534eb1090483c96178fcb0f8893719d96d5274dfde98aa6add34614e97c8e \
+ --hash=sha256:f3f6fdfa89ee2d9d496e2c087cebef9d4fcbb0ad63c40e821b39f74bf48d9c5e \
+ --hash=sha256:f53c2c87e0fb4b0c00fa9571082a057e37690a8f12233306161c8f4b819960b7 \
+ --hash=sha256:f5e7cb1e5e56ca0933b4873c0220a78b773b24d40d186b6738080b73d3d0a756 \
+ --hash=sha256:f677e1268c4e23420c3acade68fac427fffcb8d19d7df95ed7ad17cdef8404f4
# via secretstorage
-docutils==0.19
+docutils==0.21.2 \
+ --hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
+ --hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
# via readme-renderer
-idna==3.4
+id==1.5.0 \
+ --hash=sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d \
+ --hash=sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658
+ # via twine
+idna==3.10 \
+ --hash=sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9 \
+ --hash=sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3
# via requests
-importlib-metadata==6.0.0
- # via
- # keyring
- # twine
-jaraco-classes==3.2.3
+jaraco-classes==3.4.0 \
+ --hash=sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd \
+ --hash=sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790
+ # via keyring
+jaraco-context==6.0.1 \
+ --hash=sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3 \
+ --hash=sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4
+ # via keyring
+jaraco-functools==4.1.0 \
+ --hash=sha256:70f7e0e2ae076498e212562325e805204fc092d7b4c17e0e86c959e249701a9d \
+ --hash=sha256:ad159f13428bc4acbf5541ad6dec511f91573b90fba04df61dafa2a1231cf649
# via keyring
-jeepney==0.8.0
+jeepney==0.8.0 \
+ --hash=sha256:5efe48d255973902f6badc3ce55e2aa6c5c3b3bc642059ef3a91247bcfcc5806 \
+ --hash=sha256:c0a454ad016ca575060802ee4d590dd912e35c122fa04e70306de3d076cce755
# via
# keyring
# secretstorage
-keyring==23.13.1
+keyring==25.6.0 \
+ --hash=sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66 \
+ --hash=sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd
# via twine
-markdown-it-py==2.1.0
+markdown-it-py==3.0.0 \
+ --hash=sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1 \
+ --hash=sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb
# via rich
-mdurl==0.1.2
+mdurl==0.1.2 \
+ --hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \
+ --hash=sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba
# via markdown-it-py
-more-itertools==9.0.0
- # via jaraco-classes
-packaging==23.0
+more-itertools==10.6.0 \
+ --hash=sha256:2cd7fad1009c31cc9fb6a035108509e6547547a7a738374f10bd49a09eb3ee3b \
+ --hash=sha256:6eb054cb4b6db1473f6e15fcc676a08e4732548acd47c708f0e179c2c7c01e89
+ # via
+ # jaraco-classes
+ # jaraco-functools
+nh3==0.2.20 \
+ --hash=sha256:09f037c02fc2c43b211ff1523de32801dcfb0918648d8e651c36ef890f1731ec \
+ --hash=sha256:0ae9cbd713524cdb81e64663d0d6aae26f678db9f2cd9db0bf162606f1f9f20c \
+ --hash=sha256:10317cd96fe4bbd4eb6b95f3920b71c902157ad44fed103fdcde43e3b8ee8be6 \
+ --hash=sha256:181063c581defe683bd4bb78188ac9936d208aebbc74c7f7c16b6a32ae2ebb38 \
+ --hash=sha256:1b9a8340a0aab991c68a5ca938d35ef4a8a3f4bf1b455da8855a40bee1fa0ace \
+ --hash=sha256:231addb7643c952cd6d71f1c8702d703f8fe34afcb20becb3efb319a501a12d7 \
+ --hash=sha256:3eb04b9c3deb13c3a375ea39fd4a3c00d1f92e8fb2349f25f1e3e4506751774b \
+ --hash=sha256:47b2946c0e13057855209daeffb45dc910bd0c55daf10190bb0b4b60e2999784 \
+ --hash=sha256:4fd2e9248725ebcedac3997a8d3da0d90a12a28c9179c6ba51f1658938ac30d0 \
+ --hash=sha256:6ed834c68452a600f517dd3e1534dbfaff1f67f98899fecf139a055a25d99150 \
+ --hash=sha256:76e2f603b30c02ff6456b233a83fc377dedab6a50947b04e960a6b905637b776 \
+ --hash=sha256:813f1c8012dd64c990514b795508abb90789334f76a561fa0fd4ca32d2275330 \
+ --hash=sha256:8698db4c04b140800d1a1cd3067fda399e36e1e2b8fc1fe04292a907350a3e9b \
+ --hash=sha256:92f3f1c4f47a2c6f3ca7317b1d5ced05bd29556a75d3a4e2715652ae9d15c05d \
+ --hash=sha256:9705c42d7ff88a0bea546c82d7fe5e59135e3d3f057e485394f491248a1f8ed5 \
+ --hash=sha256:ac4d27dc836a476efffc6eb661994426b8b805c951b29c9cf2ff36bc9ad58bc5 \
+ --hash=sha256:ce3731c8f217685d33d9268362e5b4f770914e922bba94d368ab244a59a6c397 \
+ --hash=sha256:d2a176fd4306b6f0f178a3f67fac91bd97a3a8d8fafb771c9b9ef675ba5c8886 \
+ --hash=sha256:da87573f03084edae8eb87cfe811ec338606288f81d333c07d2a9a0b9b976c0b \
+ --hash=sha256:ddefa9fd6794a87e37d05827d299d4b53a3ec6f23258101907b96029bfef138a \
+ --hash=sha256:e1061a4ab6681f6bdf72b110eea0c4e1379d57c9de937db3be4202f7ad6043db \
+ --hash=sha256:e1f7370b4e14cc03f5ae141ef30a1caf81fa5787711f80be9081418dd9eb79d2 \
+ --hash=sha256:eb4254b1dac4a1ee49919a5b3f1caf9803ea8dada1816d9e8289e63d3cd0dd9a \
+ --hash=sha256:f7d564871833ddbe54df3aa59053b1110729d3a800cb7628ae8f42adb3d75208
+ # via readme-renderer
+packaging==24.2 \
+ --hash=sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759 \
+ --hash=sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f
# via
- # build
# check-wheel-contents
-pkginfo==1.9.6
- # via twine
-pycparser==2.21
+ # twine
+pycparser==2.22 \
+ --hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
+ --hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
# via cffi
-pydantic==1.10.4
+pydantic==2.10.5 \
+ --hash=sha256:278b38dbbaec562011d659ee05f63346951b3a248a6f3642e1bc68894ea2b4ff \
+ --hash=sha256:4dd4e322dbe55472cb7ca7e73f4b63574eecccf2835ffa2af9021ce113c83c53
# via check-wheel-contents
-pygments==2.14.0
+pydantic-core==2.27.2 \
+ --hash=sha256:00bad2484fa6bda1e216e7345a798bd37c68fb2d97558edd584942aa41b7d278 \
+ --hash=sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50 \
+ --hash=sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9 \
+ --hash=sha256:044a50963a614ecfae59bb1eaf7ea7efc4bc62f49ed594e18fa1e5d953c40e9f \
+ --hash=sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6 \
+ --hash=sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc \
+ --hash=sha256:097830ed52fd9e427942ff3b9bc17fab52913b2f50f2880dc4a5611446606a54 \
+ --hash=sha256:0d1e85068e818c73e048fe28cfc769040bb1f475524f4745a5dc621f75ac7630 \
+ --hash=sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9 \
+ --hash=sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236 \
+ --hash=sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7 \
+ --hash=sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee \
+ --hash=sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b \
+ --hash=sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048 \
+ --hash=sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc \
+ --hash=sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130 \
+ --hash=sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4 \
+ --hash=sha256:251136cdad0cb722e93732cb45ca5299fb56e1344a833640bf93b2803f8d1bfd \
+ --hash=sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4 \
+ --hash=sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7 \
+ --hash=sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7 \
+ --hash=sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4 \
+ --hash=sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e \
+ --hash=sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa \
+ --hash=sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6 \
+ --hash=sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962 \
+ --hash=sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b \
+ --hash=sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f \
+ --hash=sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474 \
+ --hash=sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5 \
+ --hash=sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459 \
+ --hash=sha256:42c5f762659e47fdb7b16956c71598292f60a03aa92f8b6351504359dbdba6cf \
+ --hash=sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a \
+ --hash=sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c \
+ --hash=sha256:4c9775e339e42e79ec99c441d9730fccf07414af63eac2f0e48e08fd38a64d76 \
+ --hash=sha256:4e0b4220ba5b40d727c7f879eac379b822eee5d8fff418e9d3381ee45b3b0362 \
+ --hash=sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4 \
+ --hash=sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934 \
+ --hash=sha256:521eb9b7f036c9b6187f0b47318ab0d7ca14bd87f776240b90b21c1f4f149320 \
+ --hash=sha256:57762139821c31847cfb2df63c12f725788bd9f04bc2fb392790959b8f70f118 \
+ --hash=sha256:5e4f4bb20d75e9325cc9696c6802657b58bc1dbbe3022f32cc2b2b632c3fbb96 \
+ --hash=sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306 \
+ --hash=sha256:669e193c1c576a58f132e3158f9dfa9662969edb1a250c54d8fa52590045f046 \
+ --hash=sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3 \
+ --hash=sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2 \
+ --hash=sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af \
+ --hash=sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9 \
+ --hash=sha256:77d1bca19b0f7021b3a982e6f903dcd5b2b06076def36a652e3907f596e29f67 \
+ --hash=sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a \
+ --hash=sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27 \
+ --hash=sha256:7d0c8399fcc1848491f00e0314bd59fb34a9c008761bcb422a057670c3f65e35 \
+ --hash=sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b \
+ --hash=sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151 \
+ --hash=sha256:8083d4e875ebe0b864ffef72a4304827015cff328a1be6e22cc850753bfb122b \
+ --hash=sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154 \
+ --hash=sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133 \
+ --hash=sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef \
+ --hash=sha256:85210c4d99a0114f5a9481b44560d7d1e35e32cc5634c656bc48e590b669b145 \
+ --hash=sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15 \
+ --hash=sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4 \
+ --hash=sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc \
+ --hash=sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee \
+ --hash=sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c \
+ --hash=sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0 \
+ --hash=sha256:9fdbe7629b996647b99c01b37f11170a57ae675375b14b8c13b8518b8320ced5 \
+ --hash=sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57 \
+ --hash=sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b \
+ --hash=sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8 \
+ --hash=sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1 \
+ --hash=sha256:bca101c00bff0adb45a833f8451b9105d9df18accb8743b08107d7ada14bd7da \
+ --hash=sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e \
+ --hash=sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc \
+ --hash=sha256:c10eb4f1659290b523af58fa7cffb452a61ad6ae5613404519aee4bfbf1df993 \
+ --hash=sha256:c33939a82924da9ed65dab5a65d427205a73181d8098e79b6b426bdf8ad4e656 \
+ --hash=sha256:c61709a844acc6bf0b7dce7daae75195a10aac96a596ea1b776996414791ede4 \
+ --hash=sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c \
+ --hash=sha256:c817e2b40aba42bac6f457498dacabc568c3b7a986fc9ba7c8d9d260b71485fb \
+ --hash=sha256:cabb9bcb7e0d97f74df8646f34fc76fbf793b7f6dc2438517d7a9e50eee4f14d \
+ --hash=sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9 \
+ --hash=sha256:cca63613e90d001b9f2f9a9ceb276c308bfa2a43fafb75c8031c4f66039e8c6e \
+ --hash=sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1 \
+ --hash=sha256:d2088237af596f0a524d3afc39ab3b036e8adb054ee57cbb1dcf8e09da5b29cc \
+ --hash=sha256:d262606bf386a5ba0b0af3b97f37c83d7011439e3dc1a9298f21efb292e42f1a \
+ --hash=sha256:d2d63f1215638d28221f664596b1ccb3944f6e25dd18cd3b86b0a4c408d5ebb9 \
+ --hash=sha256:d3e8d504bdd3f10835468f29008d72fc8359d95c9c415ce6e767203db6127506 \
+ --hash=sha256:d4041c0b966a84b4ae7a09832eb691a35aec90910cd2dbe7a208de59be77965b \
+ --hash=sha256:d716e2e30c6f140d7560ef1538953a5cd1a87264c737643d481f2779fc247fe1 \
+ --hash=sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d \
+ --hash=sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99 \
+ --hash=sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3 \
+ --hash=sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31 \
+ --hash=sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c \
+ --hash=sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39 \
+ --hash=sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a \
+ --hash=sha256:ef592d4bad47296fb11f96cd7dc898b92e795032b4894dfb4076cfccd43a9308 \
+ --hash=sha256:f141ee28a0ad2123b6611b6ceff018039df17f32ada8b534e6aa039545a3efb2 \
+ --hash=sha256:f66d89ba397d92f840f8654756196d93804278457b5fbede59598a1f9f90b228 \
+ --hash=sha256:f6f8e111843bbb0dee4cb6594cdc73e79b3329b526037ec242a3e49012495b3b \
+ --hash=sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9 \
+ --hash=sha256:fd1aea04935a508f62e0d0ef1f5ae968774a32afc306fb8545e06f5ff5cdf3ad
+ # via pydantic
+pygments==2.19.1 \
+ --hash=sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f \
+ --hash=sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c
# via
# readme-renderer
# rich
-pyproject-hooks==1.0.0
- # via build
-readme-renderer==37.3
+readme-renderer==44.0 \
+ --hash=sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151 \
+ --hash=sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1
# via twine
-requests==2.28.2
+requests==2.32.3 \
+ --hash=sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760 \
+ --hash=sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6
# via
+ # id
# requests-toolbelt
# twine
-requests-toolbelt==0.10.1
+requests-toolbelt==1.0.0 \
+ --hash=sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6 \
+ --hash=sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06
# via twine
-rfc3986==2.0.0
+rfc3986==2.0.0 \
+ --hash=sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd \
+ --hash=sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c
# via twine
-rich==13.3.1
+rich==13.9.4 \
+ --hash=sha256:439594978a49a09530cff7ebc4b5c7103ef57baf48d5ea3184f21d9a2befa098 \
+ --hash=sha256:6049d5e6ec054bf2779ab3358186963bac2ea89175919d699e378b99738c2a90
# via twine
-secretstorage==3.3.3
+secretstorage==3.3.3 \
+ --hash=sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77 \
+ --hash=sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99
# via keyring
-six==1.16.0
- # via bleach
-tomli==2.0.1
- # via
- # build
- # check-wheel-contents
- # pyproject-hooks
-twine==4.0.2
+twine==6.1.0 \
+ --hash=sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384 \
+ --hash=sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd
# via -r requirements/tools.in
-typing-extensions==4.4.0
- # via pydantic
-urllib3==1.26.14
+typing-extensions==4.12.2 \
+ --hash=sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d \
+ --hash=sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8
+ # via
+ # pydantic
+ # pydantic-core
+urllib3==2.3.0 \
+ --hash=sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df \
+ --hash=sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d
# via
# requests
# twine
-webencodings==0.5.1
- # via bleach
-wheel==0.38.4
+wheel==0.45.1 \
+ --hash=sha256:661e1abd9198507b1409a20c02106d9670b2576e916d58f520316666abca6729 \
+ --hash=sha256:708e7481cc80179af0e556bbf0cc00b8444c7321e2700b8d8580231d13017248
# via -r requirements/tools.in
-wheel-filename==1.4.1
+wheel-filename==1.4.2 \
+ --hash=sha256:3fa599046443d4ca830d06e3d180cd0a675d5871af0a68daa5623318bb4d17e3 \
+ --hash=sha256:87891c465dcbb40b40394a906f01a93214bdd51aa5d25e3a9a59cae62bc298fd
# via check-wheel-contents
-zipp==3.12.1
- # via importlib-metadata