diff --git a/.github/workflows/release-pypi.yml b/.github/workflows/release-pypi.yml index 4bd55f90..7ba76417 100644 --- a/.github/workflows/release-pypi.yml +++ b/.github/workflows/release-pypi.yml @@ -82,6 +82,8 @@ jobs: # REFER: GITHUB_REF is the branch ref or tag that triggered the workflow run. # https://docs.github.com/en/actions/learn-github-actions/variables#default-environment-variables - name: Probe version tag (not workflow_dispatch) + if: github.event_name != 'workflow_dispatch' + shell: bash run: | VERSION_TAG="${GITHUB_REF#refs/tags/}" @@ -100,21 +102,19 @@ jobs: fi echo "VERSION_TAG=${VERSION_TAG}" >> "${GITHUB_ENV}" - shell: bash - if: github.event_name != 'workflow_dispatch' - name: Checkout repository (not workflow_dispatch) - uses: actions/checkout@v4 if: github.event_name != 'workflow_dispatch' + uses: actions/checkout@v4 - name: Checkout repository (is workflow_dispatch) + if: github.event_name == 'workflow_dispatch' uses: actions/checkout@v4 with: ref: ${{ github.event.repository.default_branch }} # Grab everything, because we might need to switch branches # in the next step. fetch-depth: 0 - if: github.event_name == 'workflow_dispatch' # Check the default branch HEAD for a version tag. # - If it's not found, try the pre-release branch. @@ -198,8 +198,8 @@ jobs: # ~/.kit/sh/sh-git-nubs/bin/git-nubs.sh # git_latest_version_tag - name: Fail if VERSION_TAG undiscoverable - run: exit 1 if: env.VERSION_TAG == '' + run: exit 1 # Double-check tag is version-formatted, esp. if 'workflow_dispatch' # (which got whatever was tagged on HEAD). @@ -221,6 +221,7 @@ jobs: shell: bash - name: Set pipx index URL + shell: bash run: | test_pypi_url="https://test.pypi.org/simple" # REFER: https://packaging.python.org/en/latest/guides/using-testpypi/ @@ -246,7 +247,6 @@ jobs: && index_url_pipx="" \ || index_url_pipx="--index-url ${test_pypi_url} ${pipx_pip_args}" echo INDEX_PIPX=${index_url_pipx} >> "${GITHUB_ENV}" - shell: bash # MAYBE/2023-11-11: Prefer `fromJSON(shell-bool)` vs. `== 'true|false'`? - name: Announcement — ${{ @@ -261,8 +261,8 @@ jobs: # github.repository is, e.g.,"doblabs/easy-as-pypi". - name: Probe package name - run: echo "PACKAGE_NAME=$(basename ${{ github.repository }})" >> "${GITHUB_ENV}" shell: bash + run: echo "PACKAGE_NAME=$(basename ${{ github.repository }})" >> "${GITHUB_ENV}" # # Local, and GHA: 1.2.0. # - name: pipx --version @@ -271,22 +271,22 @@ jobs: # On GHA: pipx: error: unrecognized arguments: easy-as-pypi==1.1.1a20 - name: Check if previously released + shell: bash run: | IS_RELEASED=false echo "pip install ${INDEX_PIP} ${PACKAGE_NAME}==${VERSION}" pip install ${INDEX_PIP} ${PACKAGE_NAME}==${VERSION} \ && IS_RELEASED=true echo "IS_RELEASED=${IS_RELEASED}" >> "${GITHUB_ENV}" - shell: bash # Determine if previously released (and skip re-releasing if so). - name: View release + if: env.IS_RELEASED == 'true' run: | echo "gh release view ${VERSION_TAG}" gh release view ${VERSION_TAG} env: GH_TOKEN: ${{ github.token }} - if: env.IS_RELEASED == 'true' # Here's how you might publish using Poetry, but this approach # requires a PyPI token. @@ -363,20 +363,17 @@ jobs: wrangle-ci-tags: name: Wrangle (read) CI tags - uses: ./.github/workflows/ci-tags-wrangle.yml needs: [prepare-publish] if: ${{ ! cancelled() && needs.prepare-publish.result == 'success' && needs.prepare-publish.outputs.IS_RELEASED == 'false' }} + uses: ./.github/workflows/ci-tags-wrangle.yml with: prerelease: ${{ needs.prepare-publish.outputs.PRERELEASE == 'true' }} # *** poetry-publish: - - runs-on: ubuntu-latest - needs: [prepare-publish, wrangle-ci-tags] # Easiest approach would be to skip if IS_RELEASED, e.g., @@ -390,6 +387,8 @@ jobs: && needs.prepare-publish.outputs.IS_RELEASED == 'false' && needs.wrangle-ci-tags.outputs.old-inhibit-release-pypi == 'false' }} + runs-on: ubuntu-latest + # CXREF: PyPI recommends using an environment ('release') # to keep non-admin organization members from publishing. # - BWARE: The environment configuration's branch protection rules @@ -460,9 +459,6 @@ jobs: # https://github.com/pypa/gh-action-pypi-publish - name: Publish package distributions to test.PyPI - uses: pypa/gh-action-pypi-publish@release/v1 - with: - repository-url: https://test.pypi.org/legacy/ # Only publish pre-release packages to test.PyPI. # # - It's not prudent to publish normal packages to test.PyPI, @@ -481,12 +477,15 @@ jobs: # - So for either type or release cascade, whether 'alpha' # or 'patch', we always publish to the same package index. if: env.PRERELEASE == 'true' + uses: pypa/gh-action-pypi-publish@release/v1 + with: + repository-url: https://test.pypi.org/legacy/ - name: Publish package distributions to PyPI - uses: pypa/gh-action-pypi-publish@release/v1 # Unlike test.PyPI, only publish normal releases to PyPI proper, # never alphas. if: env.PRERELEASE == 'false' + uses: pypa/gh-action-pypi-publish@release/v1 # *** @@ -512,9 +511,9 @@ jobs: # immediately, but it takes a bit for pip to find it (~12 sec). # - SAVVY/2023-10-08: Huh, 17s not always enough? - name: Sleep for 13 seconds - run: sleep 13s - shell: bash if: needs.prepare-publish.outputs.IS_RELEASED == 'false' + shell: bash + run: sleep 13s # *** diff --git a/.github/workflows/release-smoke-test.yml b/.github/workflows/release-smoke-test.yml index 48c89e5c..8224068e 100644 --- a/.github/workflows/release-smoke-test.yml +++ b/.github/workflows/release-smoke-test.yml @@ -33,12 +33,9 @@ on: # *** env: - # Lest: "The `python-version` input is not set. The version - # of Python currently in `PATH` will be used." and - # "Cache paths are empty. Please check the previous - # logs and make sure that the python version is specified" - # TRACK: https://github.com/actions/python-versions/releases - # USYNC: workflows/ (PYTHON_VERSION), tox.ini (basepython), Makefile (VENV_PYVER). + # USYNC: When you update Python versions, update the following: + # workflows/ (PYTHON_VERSION), tox.ini (basepython), Makefile (VENV_PYVER) + # - REFER: Track versions at https://github.com/actions/python-versions/releases # BWARE: Trailing zeroes disappear unless quoted. PYTHON_VERSION: "3.11" diff --git a/README.rst b/README.rst index 1627557d..ba5dd321 100644 --- a/README.rst +++ b/README.rst @@ -49,39 +49,142 @@ Overview Boilerplate for modern, bathroom-tub-included Python projects. -The boilerplate itself is installable and includes minimalist Click CLI. +This project is installable and includes a minimalist +`Click `__ CLI:: -But most of the gold is buried within: + pip install easy-as-pypi + + easy-as-pypi + +But this project is so much more! + +This is *living* boilerplate. + +- Use this project to start a new Python project. + +- Use this project to manage your CI checks. + +- Use this project to automate your releases. + +- And keep your project up-to-date with the latest "boilerplate" by running:: + + bin/update-faithful + +- Because boilerplate is *never* static! + +Here are the selling points, because we're all here to make gold: - Modern Poetry and ``pyproject.toml`` setup. -- Supports cascading editable installs (install current project in - editable mode, as well as any dependencies you might have source - for locally; boilerplate manages alternative ``pyproject.toml`` - automatically). + - Much of any project's ``pyproject.toml`` is already prescribed, like, + 90% of your projects' ``pyproject.toml`` is the same between all your + projects. + + - So this project *generates* ``pyproject.toml``. + + It uses a simple template, located at ``.pyproject.project.tmpl``, + and applies it to a base ``pyproject.toml`` template + (named ``.pyproject.tmpl``). + + - Use ``.pyproject.project.tmpl`` to add the few bits that are unique + to your project, then run ``bin/update-faithful`` to generate + ``pyproject.toml`` for your project. + + - Most of ``pyproject.toml`` is already boilerplate — think of + ``pytest`` options, ``black`` options, ``flake8`` options, + ``isort`` options, as well as ``poetry install --with`` + dependencies, like those for testing, or creating docs, + etc. — these are usually the same for all of your projects! + So why repeat yourself? + + As such, we consider ``pyproject.toml`` to be essentially + boilerplate — it's half boilerplate, half project-specific, + and generated when you run ``bin/update-faithful``. + +- *Editable* installs. + + - Run ``make develop`` to install your project in editable mode, + as well as any dependencies that you have sources for locally. + + - This project (the boilerplate) will manage an alternative + ``.pyproject-editable/pyproject.toml`` automatically. + + - Edit ``Makefile`` to tell it which projects are *editable* + (specifically the ``EDITABLE_PJS`` environ). + +- Pre-release installs. + + - Publish pre-release builds to https://test.pypi.org + + - This project (the boilerplate) manages an alternative + ``.pyproject-prerelease/pyproject.toml`` and ``poetry.lock``, + as well as using the appropriate ``pip install --pre`` options, + so you can test changes to your stack before releasing to PyPI, + +- All the lints. + + - Run ``make lint`` to run all the lints: ``black``, ``flake8``, + ``isort``, ``pydocstyle``, ``doc8``, ``linkcheck``, + ``poetry check``, and ``twine check``. + +- All the tests. + + - Run ``tox`` to test against all supported Python versions. + +- All the other dev tasks. + + - Run ``make develop`` to create an editable virtualenv (using local sources). + + - Then you can run your app locally, against local sources, + by calling ``make test``, or ``pytest``. + + - You can also use ``pyenv`` and modify the Python version in + ``Makefile`` to test against different Python versions, e.g.,:: + + pyenv install -s 3.12 + + sed -i 's/^VENV_PYVER.*/VENV_PYVER ?= 3.12/' Makefile + + make develop + + workon + + make test + + - Run ``make install`` to create a release virtualenv (using PyPI sources), + so you can test what end-users will experience (though not the same as + publishing to PyPI and running ``pip install``, but close). + + - Run ``make docs`` to generate docs for *ReadTheDocs*. + + - Run ``make coverage`` to, ya know, run coverage. + + - Also Babel support, e.g., run ``make babel-compile`` to localize user + messages. -- All the lints: ``black``, ``flake8``, ``isort``, ``pydocstyle``, - ``doc8``, ``linkcheck``, ``poetry check``, and ``twine check``. +- All the CI. -- Test against all active Python versions and lint using ``tox``. + - Look under ``.github/workflows`` for what some might consider an + over-engineered GitHub Actions workflow. -- Run tasks, tests, and setup virtualenvs quickly using ``make`` - commands in your active virtualenv. + But that's really where's there gold: - - Generate docs for *ReadTheDocs*. + - When you push a branch, checks run. - - Localize user messages using ``Babel``. + - When you push a version tag, a release happens. - - Easily install to shared or isolated virtualenvs. + - After checks run, and after a release is published, + a "smoke test" runs: Both ``pip`` and ``pipx`` are + called to verify your package is viable. -- GitHub Actions linting, testing, and coverage upload. + - And lemme tell you, Poetry might work, publishing + to PyPI might work, but that still doesn't mean + the release works. The smoke test lets you know + it works for certain. -Most of the files are designed to be hard linked from the derived -projects themselves, as they won't need to be customized (such as -``Makefile``). + - And if you maintain multiple projects, the CI job + will dispatch and kick-off the release of the next + downstream project. -- Then when the boilerplate changes, you can just commit the - changes in the derived project, call them "dependency updates" - or something, and not have to worry about merging changes manually - (and running ``meld`` or something). +Point being, this is the Python "boilerplate" to end all boilerplate. diff --git a/poetry.lock b/poetry.lock index d16dc692..018363f2 100644 --- a/poetry.lock +++ b/poetry.lock @@ -444,47 +444,56 @@ toml = ["tomli"] [[package]] name = "cryptography" -version = "41.0.7" +version = "42.0.4" description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." optional = false python-versions = ">=3.7" files = [ - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:3c78451b78313fa81607fa1b3f1ae0a5ddd8014c38a02d9db0616133987b9cdf"}, - {file = "cryptography-41.0.7-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:928258ba5d6f8ae644e764d0f996d61a8777559f72dfeb2eea7e2fe0ad6e782d"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a1b41bc97f1ad230a41657d9155113c7521953869ae57ac39ac7f1bb471469a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:841df4caa01008bad253bce2a6f7b47f86dc9f08df4b433c404def869f590a15"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:5429ec739a29df2e29e15d082f1d9ad683701f0ec7709ca479b3ff2708dae65a"}, - {file = "cryptography-41.0.7-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:43f2552a2378b44869fe8827aa19e69512e3245a219104438692385b0ee119d1"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:af03b32695b24d85a75d40e1ba39ffe7db7ffcb099fe507b39fd41a565f1b157"}, - {file = "cryptography-41.0.7-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:49f0805fc0b2ac8d4882dd52f4a3b935b210935d500b6b805f321addc8177406"}, - {file = "cryptography-41.0.7-cp37-abi3-win32.whl", hash = "sha256:f983596065a18a2183e7f79ab3fd4c475205b839e02cbc0efbbf9666c4b3083d"}, - {file = "cryptography-41.0.7-cp37-abi3-win_amd64.whl", hash = "sha256:90452ba79b8788fa380dfb587cca692976ef4e757b194b093d845e8d99f612f2"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:079b85658ea2f59c4f43b70f8119a52414cdb7be34da5d019a77bf96d473b960"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:b640981bf64a3e978a56167594a0e97db71c89a479da8e175d8bb5be5178c003"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:e3114da6d7f95d2dee7d3f4eec16dacff819740bbab931aff8648cb13c5ff5e7"}, - {file = "cryptography-41.0.7-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:d5ec85080cce7b0513cfd233914eb8b7bbd0633f1d1703aa28d1dd5a72f678ec"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-macosx_10_12_x86_64.whl", hash = "sha256:7a698cb1dac82c35fcf8fe3417a3aaba97de16a01ac914b89a0889d364d2f6be"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:37a138589b12069efb424220bf78eac59ca68b95696fc622b6ccc1c0a197204a"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:68a2dec79deebc5d26d617bfdf6e8aab065a4f34934b22d3b5010df3ba36612c"}, - {file = "cryptography-41.0.7-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:09616eeaef406f99046553b8a40fbf8b1e70795a91885ba4c96a70793de5504a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:48a0476626da912a44cc078f9893f292f0b3e4c739caf289268168d8f4702a39"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:c7f3201ec47d5207841402594f1d7950879ef890c0c495052fa62f58283fde1a"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:c5ca78485a255e03c32b513f8c2bc39fedb7f5c5f8535545bdc223a03b24f248"}, - {file = "cryptography-41.0.7-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:d6c391c021ab1f7a82da5d8d0b3cee2f4b2c455ec86c8aebbc84837a631ff309"}, - {file = "cryptography-41.0.7.tar.gz", hash = "sha256:13f93ce9bea8016c253b34afc6bd6a75993e5c40672ed5405a9c832f0d4a00bc"}, + {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_universal2.whl", hash = "sha256:ffc73996c4fca3d2b6c1c8c12bfd3ad00def8621da24f547626bf06441400449"}, + {file = "cryptography-42.0.4-cp37-abi3-macosx_10_12_x86_64.whl", hash = "sha256:db4b65b02f59035037fde0998974d84244a64c3265bdef32a827ab9b63d61b18"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dad9c385ba8ee025bb0d856714f71d7840020fe176ae0229de618f14dae7a6e2"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:69b22ab6506a3fe483d67d1ed878e1602bdd5912a134e6202c1ec672233241c1"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:e09469a2cec88fb7b078e16d4adec594414397e8879a4341c6ace96013463d5b"}, + {file = "cryptography-42.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3e970a2119507d0b104f0a8e281521ad28fc26f2820687b3436b8c9a5fcf20d1"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:e53dc41cda40b248ebc40b83b31516487f7db95ab8ceac1f042626bc43a2f992"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:c3a5cbc620e1e17009f30dd34cb0d85c987afd21c41a74352d1719be33380885"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bfadd884e7280df24d26f2186e4e07556a05d37393b0f220a840b083dc6a824"}, + {file = "cryptography-42.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:01911714117642a3f1792c7f376db572aadadbafcd8d75bb527166009c9f1d1b"}, + {file = "cryptography-42.0.4-cp37-abi3-win32.whl", hash = "sha256:fb0cef872d8193e487fc6bdb08559c3aa41b659a7d9be48b2e10747f47863925"}, + {file = "cryptography-42.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:c1f25b252d2c87088abc8bbc4f1ecbf7c919e05508a7e8628e6875c40bc70923"}, + {file = "cryptography-42.0.4-cp39-abi3-macosx_10_12_universal2.whl", hash = "sha256:15a1fb843c48b4a604663fa30af60818cd28f895572386e5f9b8a665874c26e7"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1327f280c824ff7885bdeef8578f74690e9079267c1c8bd7dc5cc5aa065ae52"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6ffb03d419edcab93b4b19c22ee80c007fb2d708429cecebf1dd3258956a563a"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:1df6fcbf60560d2113b5ed90f072dc0b108d64750d4cbd46a21ec882c7aefce9"}, + {file = "cryptography-42.0.4-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:44a64043f743485925d3bcac548d05df0f9bb445c5fcca6681889c7c3ab12764"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_aarch64.whl", hash = "sha256:3c6048f217533d89f2f8f4f0fe3044bf0b2090453b7b73d0b77db47b80af8dff"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_1_x86_64.whl", hash = "sha256:6d0fbe73728c44ca3a241eff9aefe6496ab2656d6e7a4ea2459865f2e8613257"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:887623fe0d70f48ab3f5e4dbf234986b1329a64c066d719432d0698522749929"}, + {file = "cryptography-42.0.4-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:ce8613beaffc7c14f091497346ef117c1798c202b01153a8cc7b8e2ebaaf41c0"}, + {file = "cryptography-42.0.4-cp39-abi3-win32.whl", hash = "sha256:810bcf151caefc03e51a3d61e53335cd5c7316c0a105cc695f0959f2c638b129"}, + {file = "cryptography-42.0.4-cp39-abi3-win_amd64.whl", hash = "sha256:a0298bdc6e98ca21382afe914c642620370ce0470a01e1bef6dd9b5354c36854"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5f8907fcf57392cd917892ae83708761c6ff3c37a8e835d7246ff0ad251d9298"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:12d341bd42cdb7d4937b0cabbdf2a94f949413ac4504904d0cdbdce4a22cbf88"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1cdcdbd117681c88d717437ada72bdd5be9de117f96e3f4d50dab3f59fd9ab20"}, + {file = "cryptography-42.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:0e89f7b84f421c56e7ff69f11c441ebda73b8a8e6488d322ef71746224c20fce"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f1e85a178384bf19e36779d91ff35c7617c885da487d689b05c1366f9933ad74"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:d2a27aca5597c8a71abbe10209184e1a8e91c1fd470b5070a2ea60cafec35bcd"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:4e36685cb634af55e0677d435d425043967ac2f3790ec652b2b88ad03b85c27b"}, + {file = "cryptography-42.0.4-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:f47be41843200f7faec0683ad751e5ef11b9a56a220d57f300376cd8aba81660"}, + {file = "cryptography-42.0.4.tar.gz", hash = "sha256:831a4b37accef30cccd34fcb916a5d7b5be3cbbe27268a02832c3e450aea39cb"}, ] [package.dependencies] -cffi = ">=1.12" +cffi = {version = ">=1.12", markers = "platform_python_implementation != \"PyPy\""} [package.extras] docs = ["sphinx (>=5.3.0)", "sphinx-rtd-theme (>=1.1.1)"] -docstest = ["pyenchant (>=1.6.11)", "sphinxcontrib-spelling (>=4.0.1)", "twine (>=1.12.0)"] +docstest = ["pyenchant (>=1.6.11)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] nox = ["nox"] -pep8test = ["black", "check-sdist", "mypy", "ruff"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] sdist = ["build"] ssh = ["bcrypt (>=3.1.5)"] -test = ["pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test = ["certifi", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] test-randomorder = ["pytest-randomly"] [[package]] @@ -1553,6 +1562,7 @@ files = [ {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, + {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"},