From cd7bf9fad913da518177763b1459bdcb5f640f80 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Thu, 28 Aug 2025 12:19:43 +0200 Subject: [PATCH 01/14] add nox task to check build packages --- .github/workflows/checks.yml | 16 + doc/changes/unreleased.md | 4 + exasol/toolbox/nox/_lint.py | 7 + .../templates/github/workflows/checks.yml | 16 + poetry.lock | 519 +++++++++++++++++- pyproject.toml | 1 + 6 files changed, 559 insertions(+), 4 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 7588f60bb..14c24390c 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -191,3 +191,19 @@ jobs: name: coverage-python${{ matrix.python-version }}-fast path: .coverage include-hidden-files: true + + Build-Packages: + name: Build Package Check + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Tests ] + runs-on: ubuntu-24.04 + permissions: + contents: read + steps: + - name: SCM Checkout + uses: actions/checkout@v4 + + - name: Setup Python & Poetry Environment + uses: ./.github/actions/python-environment + + - name: Run Distribution Check + run: poetry run -- nox -s lint:build-packages diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 79e701b84..4af2c343a 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -1 +1,5 @@ # Unreleased + +## Feature + +* #494: Create check of built packages \ No newline at end of file diff --git a/exasol/toolbox/nox/_lint.py b/exasol/toolbox/nox/_lint.py index 890839a10..a8f6faf38 100644 --- a/exasol/toolbox/nox/_lint.py +++ b/exasol/toolbox/nox/_lint.py @@ -177,3 +177,10 @@ def import_lint(session: Session) -> None: "Please make sure you have a configuration file for the importlinter" ) _import_lint(session=session, path=path) + + +@nox.session(name="lint:build-packages", python=False) +def dist_check(session: Session) -> None: + """Checks whether your distribution’s long description will render correctly on PyPI""" + session.run("poetry", "build") + session.run("twine", "check", "./dist/*") diff --git a/exasol/toolbox/templates/github/workflows/checks.yml b/exasol/toolbox/templates/github/workflows/checks.yml index f42b72141..257a8cfe8 100644 --- a/exasol/toolbox/templates/github/workflows/checks.yml +++ b/exasol/toolbox/templates/github/workflows/checks.yml @@ -188,3 +188,19 @@ jobs: name: coverage-python${{ matrix.python-version }}-fast path: .coverage include-hidden-files: true + + Build-Packages: + name: Build Package Check + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Tests ] + runs-on: ubuntu-24.04 + permissions: + contents: read + steps: + - name: SCM Checkout + uses: actions/checkout@v4 + + - name: Setup Python & Poetry Environment + uses: ./.github/actions/python-environment + + - name: Run Distribution Check + run: poetry run -- nox -s lint:build-packages diff --git a/poetry.lock b/poetry.lock index b3471dd86..b8344bff6 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.1.4 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. [[package]] name = "accessible-pygments" @@ -164,6 +164,23 @@ files = [ [package.extras] dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)", "jinja2 (>=3.0)", "pytest (>=6.0)", "pytest-cov", "pytz", "setuptools", "tzdata ; sys_platform == \"win32\""] +[[package]] +name = "backports-tarfile" +version = "1.2.0" +description = "Backport of CPython tarfile module" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version <= \"3.11\"" +files = [ + {file = "backports.tarfile-1.2.0-py3-none-any.whl", hash = "sha256:77e284d754527b01fb1e6fa8a1afe577858ebe4e9dad8919e34c862cb399bc34"}, + {file = "backports_tarfile-1.2.0.tar.gz", hash = "sha256:d75e02c268746e1b8144c278978b6e98e85de6ad16f8e4b0844a154557eca991"}, +] + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["jaraco.test", "pytest (!=8.0.*)", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)"] + [[package]] name = "bandit" version = "1.8.6" @@ -327,6 +344,87 @@ files = [ {file = "certifi-2025.8.3.tar.gz", hash = "sha256:e564105f78ded564e3ae7c923924435e1daa7463faeab5bb932bc53ffae63407"}, ] +[[package]] +name = "cffi" +version = "1.17.1" +description = "Foreign Function Interface for Python calling C code." +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14"}, + {file = "cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6"}, + {file = "cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e"}, + {file = "cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be"}, + {file = "cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c"}, + {file = "cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401"}, + {file = "cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6"}, + {file = "cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f"}, + {file = "cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b"}, + {file = "cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655"}, + {file = "cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4"}, + {file = "cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99"}, + {file = "cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3"}, + {file = "cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8"}, + {file = "cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65"}, + {file = "cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e"}, + {file = "cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4"}, + {file = "cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed"}, + {file = "cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9"}, + {file = "cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d"}, + {file = "cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a"}, + {file = "cffi-1.17.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:636062ea65bd0195bc012fea9321aca499c0504409f413dc88af450b57ffd03b"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7eac2ef9b63c79431bc4b25f1cd649d7f061a28808cbc6c47b534bd789ef964"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e221cf152cff04059d011ee126477f0d9588303eb57e88923578ace7baad17f9"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:31000ec67d4221a71bd3f67df918b1f88f676f1c3b535a7eb473255fdc0b83fc"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6f17be4345073b0a7b8ea599688f692ac3ef23ce28e5df79c04de519dbc4912c"}, + {file = "cffi-1.17.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2b1fac190ae3ebfe37b979cc1ce69c81f4e4fe5746bb401dca63a9062cdaf1"}, + {file = "cffi-1.17.1-cp38-cp38-win32.whl", hash = "sha256:7596d6620d3fa590f677e9ee430df2958d2d6d6de2feeae5b20e82c00b76fbf8"}, + {file = "cffi-1.17.1-cp38-cp38-win_amd64.whl", hash = "sha256:78122be759c3f8a014ce010908ae03364d00a1f81ab5c7f4a7a5120607ea56e1"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b2ab587605f4ba0bf81dc0cb08a41bd1c0a5906bd59243d56bad7668a6fc6c16"}, + {file = "cffi-1.17.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28b16024becceed8c6dfbc75629e27788d8a3f9030691a1dbf9821a128b22c36"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1d599671f396c4723d016dbddb72fe8e0397082b0a77a4fab8028923bec050e8"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca74b8dbe6e8e8263c0ffd60277de77dcee6c837a3d0881d8c1ead7268c9e576"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7f5baafcc48261359e14bcd6d9bff6d4b28d9103847c9e136694cb0501aef87"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98e3969bcff97cae1b2def8ba499ea3d6f31ddfdb7635374834cf89a1a08ecf0"}, + {file = "cffi-1.17.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdf5ce3acdfd1661132f2a9c19cac174758dc2352bfe37d98aa7512c6b7178b3"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:9755e4345d1ec879e3849e62222a18c7174d65a6a92d5b346b1863912168b595"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:f1e22e8c4419538cb197e4dd60acc919d7696e5ef98ee4da4e01d3f8cfa4cc5a"}, + {file = "cffi-1.17.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:c03e868a0b3bc35839ba98e74211ed2b05d2119be4e8a0f224fba9384f1fe02e"}, + {file = "cffi-1.17.1-cp39-cp39-win32.whl", hash = "sha256:e31ae45bc2e29f6b2abd0de1cc3b9d5205aa847cafaecb8af1476a609a2f6eb7"}, + {file = "cffi-1.17.1-cp39-cp39-win_amd64.whl", hash = "sha256:d016c76bdd850f3c626af19b0542c9677ba156e4ee4fccfdd7848803533ef662"}, + {file = "cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824"}, +] + +[package.dependencies] +pycparser = "*" + [[package]] name = "cfgv" version = "3.4.0" @@ -626,6 +724,118 @@ files = [ [package.extras] toml = ["tomli ; python_full_version <= \"3.11.0a6\""] +[[package]] +name = "cryptography" +version = "43.0.3" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and python_version < \"3.11\"" +files = [ + {file = "cryptography-43.0.3-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:bf7a1932ac4176486eab36a19ed4c0492da5d97123f1406cf15e41b05e787d2e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:63efa177ff54aec6e1c0aefaa1a241232dcd37413835a9b674b6e3f0ae2bfd3e"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e1ce50266f4f70bf41a2c6dc4358afadae90e2a1e5342d3c08883df1675374f"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:443c4a81bb10daed9a8f334365fe52542771f25aedaf889fd323a853ce7377d6"}, + {file = "cryptography-43.0.3-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:74f57f24754fe349223792466a709f8e0c093205ff0dca557af51072ff47ab18"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:9762ea51a8fc2a88b70cf2995e5675b38d93bf36bd67d91721c309df184f49bd"}, + {file = "cryptography-43.0.3-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:81ef806b1fef6b06dcebad789f988d3b37ccaee225695cf3e07648eee0fc6b73"}, + {file = "cryptography-43.0.3-cp37-abi3-win32.whl", hash = "sha256:cbeb489927bd7af4aa98d4b261af9a5bc025bd87f0e3547e11584be9e9427be2"}, + {file = "cryptography-43.0.3-cp37-abi3-win_amd64.whl", hash = "sha256:f46304d6f0c6ab8e52770addfa2fc41e6629495548862279641972b6215451cd"}, + {file = "cryptography-43.0.3-cp39-abi3-macosx_10_9_universal2.whl", hash = "sha256:8ac43ae87929a5982f5948ceda07001ee5e83227fd69cf55b109144938d96984"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:846da004a5804145a5f441b8530b4bf35afbf7da70f82409f151695b127213d5"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f996e7268af62598f2fc1204afa98a3b5712313a55c4c9d434aef49cadc91d4"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f7b178f11ed3664fd0e995a47ed2b5ff0a12d893e41dd0494f406d1cf555cab7"}, + {file = "cryptography-43.0.3-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:c2e6fc39c4ab499049df3bdf567f768a723a5e8464816e8f009f121a5a9f4405"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:e1be4655c7ef6e1bbe6b5d0403526601323420bcf414598955968c9ef3eb7d16"}, + {file = "cryptography-43.0.3-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:df6b6c6d742395dd77a23ea3728ab62f98379eff8fb61be2744d4679ab678f73"}, + {file = "cryptography-43.0.3-cp39-abi3-win32.whl", hash = "sha256:d56e96520b1020449bbace2b78b603442e7e378a9b3bd68de65c782db1507995"}, + {file = "cryptography-43.0.3-cp39-abi3-win_amd64.whl", hash = "sha256:0c580952eef9bf68c4747774cde7ec1d85a6e61de97281f2dba83c7d2c806362"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:d03b5621a135bffecad2c73e9f4deb1a0f977b9a8ffe6f8e002bf6c9d07b918c"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:a2a431ee15799d6db9fe80c82b055bae5a752bef645bba795e8e52687c69efe3"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:281c945d0e28c92ca5e5930664c1cefd85efe80e5c0d2bc58dd63383fda29f83"}, + {file = "cryptography-43.0.3-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:f18c716be16bc1fea8e95def49edf46b82fccaa88587a45f8dc0ff6ab5d8e0a7"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4a02ded6cd4f0a5562a8887df8b3bd14e822a90f97ac5e544c162899bc467664"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:53a583b6637ab4c4e3591a15bc9db855b8d9dee9a669b550f311480acab6eb08"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:1ec0bcf7e17c0c5669d881b1cd38c4972fade441b27bda1051665faaa89bdcaa"}, + {file = "cryptography-43.0.3-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:2ce6fae5bdad59577b44e4dfed356944fbf1d925269114c28be377692643b4ff"}, + {file = "cryptography-43.0.3.tar.gz", hash = "sha256:315b9001266a492a6ff443b61238f956b214dbec9910a081ba5b6646a055a805"}, +] + +[package.dependencies] +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)", "readme-renderer", "sphinxcontrib-spelling (>=4.0.1)"] +nox = ["nox"] +pep8test = ["check-sdist", "click", "mypy", "ruff"] +sdist = ["build"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi", "cryptography-vectors (==43.0.3)", "pretend", "pytest (>=6.2.0)", "pytest-benchmark", "pytest-cov", "pytest-xdist"] +test-randomorder = ["pytest-randomly"] + +[[package]] +name = "cryptography" +version = "45.0.6" +description = "cryptography is a package which provides cryptographic recipes and primitives to Python developers." +optional = false +python-versions = "!=3.9.0,!=3.9.1,>=3.7" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and python_version >= \"3.11\"" +files = [ + {file = "cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402"}, + {file = "cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05"}, + {file = "cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453"}, + {file = "cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159"}, + {file = "cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec"}, + {file = "cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5"}, + {file = "cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3"}, + {file = "cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9"}, + {file = "cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02"}, + {file = "cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db"}, + {file = "cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385"}, + {file = "cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043"}, + {file = "cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719"}, +] + +[package.dependencies] +cffi = {version = ">=1.14", markers = "platform_python_implementation != \"PyPy\""} + +[package.extras] +docs = ["sphinx (>=5.3.0)", "sphinx-inline-tabs ; python_full_version >= \"3.8.0\"", "sphinx-rtd-theme (>=3.0.0) ; python_full_version >= \"3.8.0\""] +docstest = ["pyenchant (>=3)", "readme-renderer (>=30.0)", "sphinxcontrib-spelling (>=7.3.1)"] +nox = ["nox (>=2024.4.15)", "nox[uv] (>=2024.3.2) ; python_full_version >= \"3.8.0\""] +pep8test = ["check-sdist ; python_full_version >= \"3.8.0\"", "click (>=8.0.1)", "mypy (>=1.4)", "ruff (>=0.3.6)"] +sdist = ["build (>=1.0.0)"] +ssh = ["bcrypt (>=3.1.5)"] +test = ["certifi (>=2024)", "cryptography-vectors (==45.0.6)", "pretend (>=0.7)", "pytest (>=7.4.0)", "pytest-benchmark (>=4.0)", "pytest-cov (>=2.10.1)", "pytest-xdist (>=3.5.0)"] +test-randomorder = ["pytest-randomly"] + [[package]] name = "cyclonedx-python-lib" version = "9.1.0" @@ -896,6 +1106,26 @@ files = [ joblib = ">=1.3.0" typing-extensions = ">=3.10.0.0" +[[package]] +name = "id" +version = "1.5.0" +description = "A tool for generating OIDC identities" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "id-1.5.0-py3-none-any.whl", hash = "sha256:f1434e1cef91f2cbb8a4ec64663d5a23b9ed43ef44c4c957d02583d61714c658"}, + {file = "id-1.5.0.tar.gz", hash = "sha256:292cb8a49eacbbdbce97244f47a97b4c62540169c976552e497fd57df0734c1d"}, +] + +[package.dependencies] +requests = "*" + +[package.extras] +dev = ["build", "bump (>=1.3.2)", "id[lint,test]"] +lint = ["bandit", "interrogate", "mypy", "ruff (<0.8.2)", "types-requests"] +test = ["coverage[toml]", "pretend", "pytest", "pytest-cov"] + [[package]] name = "identify" version = "2.6.13" @@ -963,7 +1193,7 @@ description = "Read metadata from Python packages" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version == \"3.9\"" +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version <= \"3.11\" or python_version == \"3.9\"" files = [ {file = "importlib_metadata-8.7.0-py3-none-any.whl", hash = "sha256:e5dd1551894c77868a30651cef00984d50e1002d06942a7101d34870c5f02afd"}, {file = "importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000"}, @@ -1032,6 +1262,87 @@ files = [ colors = ["colorama"] plugins = ["setuptools"] +[[package]] +name = "jaraco-classes" +version = "3.4.0" +description = "Utility functions for Python class constructs" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco.classes-3.4.0-py3-none-any.whl", hash = "sha256:f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790"}, + {file = "jaraco.classes-3.4.0.tar.gz", hash = "sha256:47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd"}, +] + +[package.dependencies] +more-itertools = "*" + +[package.extras] +docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +testing = ["pytest (>=6)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1)"] + +[[package]] +name = "jaraco-context" +version = "6.0.1" +description = "Useful decorators and context managers" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco.context-6.0.1-py3-none-any.whl", hash = "sha256:f797fc481b490edb305122c9181830a3a5b76d84ef6d1aef2fb9b47ab956f9e4"}, + {file = "jaraco_context-6.0.1.tar.gz", hash = "sha256:9bae4ea555cf0b14938dc0aee7c9f32ed303aa20a3b73e7dc80111628792d1b3"}, +] + +[package.dependencies] +"backports.tarfile" = {version = "*", markers = "python_version < \"3.12\""} + +[package.extras] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +test = ["portend", "pytest (>=6,!=8.1.*)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] + +[[package]] +name = "jaraco-functools" +version = "4.3.0" +description = "Functools like those found in stdlib" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "jaraco_functools-4.3.0-py3-none-any.whl", hash = "sha256:227ff8ed6f7b8f62c56deff101545fa7543cf2c8e7b82a7c2116e672f29c26e8"}, + {file = "jaraco_functools-4.3.0.tar.gz", hash = "sha256:cfd13ad0dd2c47a3600b439ef72d8615d482cedcff1632930d6f28924d92f294"}, +] + +[package.dependencies] +more_itertools = "*" + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["jaraco.classes", "pytest (>=6,!=8.1.*)"] +type = ["pytest-mypy"] + +[[package]] +name = "jeepney" +version = "0.9.0" +description = "Low-level, pure Python DBus protocol wrapper." +optional = false +python-versions = ">=3.7" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +files = [ + {file = "jeepney-0.9.0-py3-none-any.whl", hash = "sha256:97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683"}, + {file = "jeepney-0.9.0.tar.gz", hash = "sha256:cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732"}, +] + +[package.extras] +test = ["async-timeout ; python_version < \"3.11\"", "pytest", "pytest-asyncio (>=0.17)", "pytest-trio", "testpath", "trio"] +trio = ["trio"] + [[package]] name = "jinja2" version = "3.1.6" @@ -1077,6 +1388,37 @@ files = [ [package.dependencies] six = ">=1.13,<2.0" +[[package]] +name = "keyring" +version = "25.6.0" +description = "Store and access your passwords safely." +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "keyring-25.6.0-py3-none-any.whl", hash = "sha256:552a3f7af126ece7ed5c89753650eec89c7eaae8617d0aa4d9ad2b75111266bd"}, + {file = "keyring-25.6.0.tar.gz", hash = "sha256:0b39998aa941431eb3d9b0d4b2460bc773b9df6fed7621c2dfb291a7e0187a66"}, +] + +[package.dependencies] +importlib_metadata = {version = ">=4.11.4", markers = "python_version < \"3.12\""} +"jaraco.classes" = "*" +"jaraco.context" = "*" +"jaraco.functools" = "*" +jeepney = {version = ">=0.4.2", markers = "sys_platform == \"linux\""} +pywin32-ctypes = {version = ">=0.2.0", markers = "sys_platform == \"win32\""} +SecretStorage = {version = ">=3.2", markers = "sys_platform == \"linux\""} + +[package.extras] +check = ["pytest-checkdocs (>=2.4)", "pytest-ruff (>=0.2.1) ; sys_platform != \"cygwin\""] +completion = ["shtab (>=1.1.0)"] +cover = ["pytest-cov"] +doc = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "rst.linker (>=1.9)", "sphinx (>=3.5)", "sphinx-lint"] +enabler = ["pytest-enabler (>=2.2)"] +test = ["pyfakefs", "pytest (>=6,!=8.1.*)"] +type = ["pygobject-stubs", "pytest-mypy", "shtab", "types-pywin32"] + [[package]] name = "license-expression" version = "30.4.4" @@ -1274,6 +1616,19 @@ files = [ {file = "mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba"}, ] +[[package]] +name = "more-itertools" +version = "10.7.0" +description = "More routines for operating on iterables, beyond itertools" +optional = false +python-versions = ">=3.9" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\"" +files = [ + {file = "more_itertools-10.7.0-py3-none-any.whl", hash = "sha256:d43980384673cb07d2f7d2d918c616b30c659c089ee23953f601d6609c67510e"}, + {file = "more_itertools-10.7.0.tar.gz", hash = "sha256:9fddd5403be01a94b204faadcff459ec3568cf110265d3c54323e1e866ad29d3"}, +] + [[package]] name = "msgpack" version = "1.1.1" @@ -1443,6 +1798,42 @@ rtd = ["ipython", "sphinx (>=7)", "sphinx-autodoc2 (>=0.5.0,<0.6.0)", "sphinx-bo testing = ["beautifulsoup4", "coverage[toml]", "defusedxml", "pytest (>=8,<9)", "pytest-cov", "pytest-param-files (>=0.6.0,<0.7.0)", "pytest-regressions", "sphinx-pytest"] testing-docutils = ["pygments", "pytest (>=8,<9)", "pytest-param-files (>=0.6.0,<0.7.0)"] +[[package]] +name = "nh3" +version = "0.3.0" +description = "Python binding to Ammonia HTML sanitizer Rust crate" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "nh3-0.3.0-cp313-cp313t-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:a537ece1bf513e5a88d8cff8a872e12fe8d0f42ef71dd15a5e7520fecd191bbb"}, + {file = "nh3-0.3.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7c915060a2c8131bef6a29f78debc29ba40859b6dbe2362ef9e5fd44f11487c2"}, + {file = "nh3-0.3.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba0caa8aa184196daa6e574d997a33867d6d10234018012d35f86d46024a2a95"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:80fe20171c6da69c7978ecba33b638e951b85fb92059259edd285ff108b82a6d"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e90883f9f85288f423c77b3f5a6f4486375636f25f793165112679a7b6363b35"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:0649464ac8eee018644aacbc103874ccbfac80e3035643c3acaab4287e36e7f5"}, + {file = "nh3-0.3.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1adeb1062a1c2974bc75b8d1ecb014c5fd4daf2df646bbe2831f7c23659793f9"}, + {file = "nh3-0.3.0-cp313-cp313t-win32.whl", hash = "sha256:7275fdffaab10cc5801bf026e3c089d8de40a997afc9e41b981f7ac48c5aa7d5"}, + {file = "nh3-0.3.0-cp313-cp313t-win_amd64.whl", hash = "sha256:423201bbdf3164a9e09aa01e540adbb94c9962cc177d5b1cbb385f5e1e79216e"}, + {file = "nh3-0.3.0-cp313-cp313t-win_arm64.whl", hash = "sha256:16f8670201f7e8e0e05ed1a590eb84bfa51b01a69dd5caf1d3ea57733de6a52f"}, + {file = "nh3-0.3.0-cp38-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:ec6cfdd2e0399cb79ba4dcffb2332b94d9696c52272ff9d48a630c5dca5e325a"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ce5e7185599f89b0e391e2f29cc12dc2e206167380cea49b33beda4891be2fe1"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:389d93d59b8214d51c400fb5b07866c2a4f79e4e14b071ad66c92184fec3a392"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:e9e6a7e4d38f7e8dda9edd1433af5170c597336c1a74b4693c5cb75ab2b30f2a"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7852f038a054e0096dac12b8141191e02e93e0b4608c4b993ec7d4ffafea4e49"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af5aa8127f62bbf03d68f67a956627b1bd0469703a35b3dad28d0c1195e6c7fb"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f416c35efee3e6a6c9ab7716d9e57aa0a49981be915963a82697952cba1353e1"}, + {file = "nh3-0.3.0-cp38-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:37d3003d98dedca6cd762bf88f2e70b67f05100f6b949ffe540e189cc06887f9"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:634e34e6162e0408e14fb61d5e69dbaea32f59e847cfcfa41b66100a6b796f62"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:b0612ccf5de8a480cf08f047b08f9d3fecc12e63d2ee91769cb19d7290614c23"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_i686.whl", hash = "sha256:c7a32a7f0d89f7d30cb8f4a84bdbd56d1eb88b78a2434534f62c71dac538c450"}, + {file = "nh3-0.3.0-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:3f1b4f8a264a0c86ea01da0d0c390fe295ea0bcacc52c2103aca286f6884f518"}, + {file = "nh3-0.3.0-cp38-abi3-win32.whl", hash = "sha256:6d68fa277b4a3cf04e5c4b84dd0c6149ff7d56c12b3e3fab304c525b850f613d"}, + {file = "nh3-0.3.0-cp38-abi3-win_amd64.whl", hash = "sha256:bae63772408fd63ad836ec569a7c8f444dd32863d0c67f6e0b25ebbd606afa95"}, + {file = "nh3-0.3.0-cp38-abi3-win_arm64.whl", hash = "sha256:d97d3efd61404af7e5721a0e74d81cdbfc6e5f97e11e731bb6d090e30a7b62b2"}, + {file = "nh3-0.3.0.tar.gz", hash = "sha256:d8ba24cb31525492ea71b6aac11a4adac91d828aadeff7c4586541bf5dc34d2f"}, +] + [[package]] name = "nodeenv" version = "1.9.1" @@ -1717,6 +2108,19 @@ files = [ [package.dependencies] defusedxml = ">=0.7.1,<0.8.0" +[[package]] +name = "pycparser" +version = "2.22" +description = "C parser in Python" +optional = false +python-versions = ">=3.8" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\" and platform_python_implementation != \"PyPy\"" +files = [ + {file = "pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc"}, + {file = "pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6"}, +] + [[package]] name = "pydantic" version = "2.11.7" @@ -2042,6 +2446,19 @@ files = [ [package.dependencies] tokenize-rt = ">=6.1.0" +[[package]] +name = "pywin32-ctypes" +version = "0.2.3" +description = "A (partial) reimplementation of pywin32 using ctypes/cffi" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"win32\"" +files = [ + {file = "pywin32-ctypes-0.2.3.tar.gz", hash = "sha256:d162dc04946d704503b2edc4d55f3dba5c1d539ead017afa00142c38b9885755"}, + {file = "pywin32_ctypes-0.2.3-py3-none-any.whl", hash = "sha256:8a1513379d709975552d202d942d9837758905c8d01eb82b8bcc30918929e7b8"}, +] + [[package]] name = "pyyaml" version = "6.0.2" @@ -2105,6 +2522,26 @@ files = [ {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] +[[package]] +name = "readme-renderer" +version = "44.0" +description = "readme_renderer is a library for rendering readme descriptions for Warehouse" +optional = false +python-versions = ">=3.9" +groups = ["main"] +files = [ + {file = "readme_renderer-44.0-py3-none-any.whl", hash = "sha256:2fbca89b81a08526aadf1357a8c2ae889ec05fb03f5da67f9769c9a592166151"}, + {file = "readme_renderer-44.0.tar.gz", hash = "sha256:8712034eabbfa6805cacf1402b4eeb2a73028f72d1166d6f5cb7f9c047c5d1e1"}, +] + +[package.dependencies] +docutils = ">=0.21.2" +nh3 = ">=0.2.14" +Pygments = ">=2.5.1" + +[package.extras] +md = ["cmarkgfm (>=0.8.0)"] + [[package]] name = "requests" version = "2.32.4" @@ -2127,6 +2564,21 @@ urllib3 = ">=1.21.1,<3" socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] +[[package]] +name = "requests-toolbelt" +version = "1.0.0" +description = "A utility belt for advanced users of python-requests" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +groups = ["main"] +files = [ + {file = "requests-toolbelt-1.0.0.tar.gz", hash = "sha256:7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6"}, + {file = "requests_toolbelt-1.0.0-py2.py3-none-any.whl", hash = "sha256:cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06"}, +] + +[package.dependencies] +requests = ">=2.0.1,<3.0.0" + [[package]] name = "responses" version = "0.25.6" @@ -2147,6 +2599,21 @@ urllib3 = ">=1.25.10,<3.0" [package.extras] tests = ["coverage (>=6.0.0)", "flake8", "mypy", "pytest (>=7.0.0)", "pytest-asyncio", "pytest-cov", "pytest-httpserver", "tomli ; python_version < \"3.11\"", "tomli-w", "types-PyYAML", "types-requests"] +[[package]] +name = "rfc3986" +version = "2.0.0" +description = "Validating URI References per RFC 3986" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "rfc3986-2.0.0-py2.py3-none-any.whl", hash = "sha256:50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd"}, + {file = "rfc3986-2.0.0.tar.gz", hash = "sha256:97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c"}, +] + +[package.extras] +idna2008 = ["idna"] + [[package]] name = "rich" version = "14.1.0" @@ -2166,6 +2633,23 @@ pygments = ">=2.13.0,<3.0.0" [package.extras] jupyter = ["ipywidgets (>=7.5.1,<9)"] +[[package]] +name = "secretstorage" +version = "3.3.3" +description = "Python bindings to FreeDesktop.org Secret Service API" +optional = false +python-versions = ">=3.6" +groups = ["main"] +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and sys_platform == \"linux\"" +files = [ + {file = "SecretStorage-3.3.3-py3-none-any.whl", hash = "sha256:f356e6628222568e3af06f2eba8df495efa13b3b63081dafd4f7d9a7b7bc9f99"}, + {file = "SecretStorage-3.3.3.tar.gz", hash = "sha256:2403533ef369eca6d2ba81718576c5e0f564d5cca1b58f73a8b23e7d4eeebd77"}, +] + +[package.dependencies] +cryptography = ">=2.0" +jeepney = ">=0.6" + [[package]] name = "setuptools" version = "80.9.0" @@ -2599,6 +3083,33 @@ files = [ {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, ] +[[package]] +name = "twine" +version = "6.1.0" +description = "Collection of utilities for publishing packages on PyPI" +optional = false +python-versions = ">=3.8" +groups = ["main"] +files = [ + {file = "twine-6.1.0-py3-none-any.whl", hash = "sha256:a47f973caf122930bf0fbbf17f80b83bc1602c9ce393c7845f289a3001dc5384"}, + {file = "twine-6.1.0.tar.gz", hash = "sha256:be324f6272eff91d07ee93f251edf232fc647935dd585ac003539b42404a8dbd"}, +] + +[package.dependencies] +id = "*" +importlib-metadata = {version = ">=3.6", markers = "python_version < \"3.10\""} +keyring = {version = ">=15.1", markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\""} +packaging = ">=24.0" +readme-renderer = ">=35.0" +requests = ">=2.20" +requests-toolbelt = ">=0.8.0,<0.9.0 || >0.9.0" +rfc3986 = ">=1.4.0" +rich = ">=12.0.0" +urllib3 = ">=1.26.0" + +[package.extras] +keyring = ["keyring (>=15.1)"] + [[package]] name = "typer" version = "0.16.0" @@ -2726,7 +3237,7 @@ description = "Backport of pathlib-compatible object wrapper for zip files" optional = false python-versions = ">=3.9" groups = ["main"] -markers = "python_version == \"3.9\"" +markers = "platform_machine != \"ppc64le\" and platform_machine != \"s390x\" and python_version <= \"3.11\" or python_version == \"3.9\"" files = [ {file = "zipp-3.23.0-py3-none-any.whl", hash = "sha256:071652d6115ed432f5ce1d34c336c0adfd6a884660d1e9712a256d3d3bd4b14e"}, {file = "zipp-3.23.0.tar.gz", hash = "sha256:a07157588a12518c9d4034df3fbbee09c814741a33ff63c05fa29d26a2404166"}, @@ -2743,4 +3254,4 @@ type = ["pytest-mypy"] [metadata] lock-version = "2.1" python-versions = ">=3.9,<4.0" -content-hash = "b65bb328dc2bca2bb79b4eedc13eb1113b5d5031b280e272c4a1606ab391cc9a" +content-hash = "559b8bc378d3bf4c21744697f861ab50d69dd3f82f28c4295566ab17191f504d" diff --git a/pyproject.toml b/pyproject.toml index b2adbaa45..0051301c3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -65,6 +65,7 @@ sphinx-copybutton = "^0.5.0" sphinx-inline-tabs = "^2023.4.21" sphinx-design = ">=0.5.0,<1" typer = { extras = ["all"], version = ">=0.7.0" } +twine = "^6.1.0" [tool.poetry.group.dev.dependencies] autoimport = "^1.4.0" From f7c9be4470fd121e72f33c4fa0ad7a3288277291 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 1 Sep 2025 10:21:12 +0200 Subject: [PATCH 02/14] Switch to rst as various local checks of bad markdown yielded no failures --- README.md | 59 ----------------------------------- README.rst | 62 +++++++++++++++++++++++++++++++++++++ exasol/toolbox/nox/_lint.py | 9 ++++-- pyproject.toml | 2 +- 4 files changed, 69 insertions(+), 63 deletions(-) delete mode 100644 README.md create mode 100644 README.rst diff --git a/README.md b/README.md deleted file mode 100644 index 0d78127c0..000000000 --- a/README.md +++ /dev/null @@ -1,59 +0,0 @@ -

Exasol Toolbox

- -

-Your one-stop solution for managing all standard tasks and core workflows of your Python project. -

- -

- - - Checks Main - - - License - - - Downloads - - - Supported Python Versions - - - PyPi Package - -

- -## 🚀 Features - -- Centrally managed standard tasks - - code formatting & upgrading - - linting - - type-checking - - unit-tests - - integration-tests - - coverage - - documentation - -- Centrally manged core workflows - - workspace/project verification - - build and publish releases - - build and publish documentation - -- Configurable & Extensible - - Project configuration - - Event hooks - -## 🔌️ Prerequisites - -- [Python](https://www.python.org/) >= 3.8 - -## 💾 Installation - -```shell -pip install exasol-toolbox -``` - -## 📚 Documentation - -For futher details, checkout the latest [documentation](https://exasol.github.io/python-toolbox/). - diff --git a/README.rst b/README.rst new file mode 100644 index 000000000..f95165566 --- /dev/null +++ b/README.rst @@ -0,0 +1,62 @@ +Exasol Toolbox +============== + +Your one-stop solution for managing all standard tasks and core workflows of your Python project. + +.. image:: https://github.com/exasol/python-toolbox/actions/workflows/ci.yml/badge.svg?branch=main + :target: https://github.com/exasol/python-toolbox/actions/workflows/ci.yml + :alt: Checks Main + +.. image:: https://img.shields.io/pypi/l/exasol-toolbox + :target: https://opensource.org/licenses/MIT + :alt: License + +.. image:: https://img.shields.io/pypi/dm/exasol-toolbox + :target: https://pypi.org/project/exasol-toolbox/ + :alt: Downloads + +.. image:: https://img.shields.io/pypi/pyversions/exasol-toolbox + :target: https://pypi.org/project/exasol-toolbox/ + :alt: Supported Python Versions + +.. image:: https://img.shields.io/pypi/v/exasol-toolbox + :target: https://pypi.org/project/exasol-toolbox/ + :alt: PyPi Package + +🚀 Features +----------- + +- Centrally managed standard tasks: + - code formatting & upgrading + - linting + - type-checking + - unit-tests + - integration-tests + - coverage + - documentation + +- Centrally managed core workflows: + - workspace/project verification + - build and publish releases + - build and publish documentation + +- Configurable & Extensible: + - Project configuration + - Event hooks + +🔌️ Prerequisites +----------------- + +- `Python `__ >= 3.9 + +💾 Installation +--------------- + +.. code-block:: shell + + pip install exasol-toolbox + +📚 Documentation +---------------- + +For further details, check out the latest `documentation `_. diff --git a/exasol/toolbox/nox/_lint.py b/exasol/toolbox/nox/_lint.py index a8f6faf38..ef9de82dc 100644 --- a/exasol/toolbox/nox/_lint.py +++ b/exasol/toolbox/nox/_lint.py @@ -181,6 +181,9 @@ def import_lint(session: Session) -> None: @nox.session(name="lint:build-packages", python=False) def dist_check(session: Session) -> None: - """Checks whether your distribution’s long description will render correctly on PyPI""" - session.run("poetry", "build") - session.run("twine", "check", "./dist/*") + """Checks whether your distribution’s long description will render correctly on PyPI + + This has more robust checks for rst documentation than markdown. + """ + session.run("poetry", "build", "--project", PROJECT_CONFIG.root) + session.run("twine", "check", PROJECT_CONFIG.root / "./dist/*") diff --git a/pyproject.toml b/pyproject.toml index 0051301c3..0baca06d2 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,7 +7,7 @@ authors = [ { name = "Nicola Coretti", email = "nicola.coretti@exasol.com" }, { name = "Ariel Schulz", email = "ariel.schulz@exasol.com" }, ] -readme = "README.md" +readme = "README.rst" license = "MIT" keywords = [ "nox", From 7e516837ef3c11c7fabf6667ad1462f0f59ca82e Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 1 Sep 2025 09:40:11 +0200 Subject: [PATCH 03/14] Add path to poetry build as when executed by pytest not in root directory --- test/unit/nox/_lint_test.py | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 test/unit/nox/_lint_test.py diff --git a/test/unit/nox/_lint_test.py b/test/unit/nox/_lint_test.py new file mode 100644 index 000000000..0a985af6c --- /dev/null +++ b/test/unit/nox/_lint_test.py @@ -0,0 +1,7 @@ +from toolbox.nox._lint import dist_check + + +class TestDistributionCheck: + @staticmethod + def test_works_as_expected(nox_session, capsys): + dist_check(nox_session) From 2b222826402d387e672580633d0f8e2b1686610d Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Mon, 1 Sep 2025 10:39:19 +0200 Subject: [PATCH 04/14] Purposefully break README.rst for test_raises_non_zero_exist_with_readme_error --- README.rst | 2 +- test/unit/nox/_lint_test.py | 17 ++++++++++++++++- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index f95165566..c93731d15 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,7 @@ Your one-stop solution for managing all standard tasks and core workflows of you 🔌️ Prerequisites ----------------- -- `Python `__ >= 3.9 +- `Python = 3.9 💾 Installation --------------- diff --git a/test/unit/nox/_lint_test.py b/test/unit/nox/_lint_test.py index 0a985af6c..e6863bc11 100644 --- a/test/unit/nox/_lint_test.py +++ b/test/unit/nox/_lint_test.py @@ -1,7 +1,22 @@ +import pytest +from nox.command import CommandFailed from toolbox.nox._lint import dist_check class TestDistributionCheck: @staticmethod - def test_works_as_expected(nox_session, capsys): + def test_works_as_expected(nox_session): dist_check(nox_session) + + @staticmethod + def test_raises_non_zero_exist_with_readme_error(nox_session): + # TODOs + # 1. copy package files to a temp directory + # 2. mock/alter the path for the function you need to use for testing + # 3. modify rst file to have a broken link like is in this commit: + # - `Python = 3.9 + + with pytest.raises(CommandFailed) as e: + dist_check(nox_session) + # verify broken with non-zero exit status + assert str(e.value) == "Returned code 1" From 4c1dca602cc7908045d4e2c1a7f19d5868a97333 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Tue, 30 Sep 2025 12:30:03 +0200 Subject: [PATCH 05/14] unfinished --- .github/workflows/checks.yml | 34 +++++++------- doc/changes/unreleased.md | 2 +- exasol/toolbox/nox/_lint.py | 10 ----- exasol/toolbox/nox/_package.py | 16 +++++++ exasol/toolbox/nox/tasks.py | 2 + .../templates/github/workflows/checks.yml | 34 +++++++------- test/unit/nox/_lint_test.py | 23 ---------- test/unit/nox/_package_check_test.py | 45 +++++++++++++++++++ 8 files changed, 98 insertions(+), 68 deletions(-) create mode 100644 exasol/toolbox/nox/_package.py delete mode 100644 test/unit/nox/_lint_test.py create mode 100644 test/unit/nox/_package_check_test.py diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 14c24390c..a5b5ccdd2 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -160,9 +160,25 @@ jobs: - name: Run format check run: poetry run -- nox -s project:format + Build-Packages: + name: Build Package Check + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + runs-on: ubuntu-24.04 + permissions: + contents: read + steps: + - name: SCM Checkout + uses: actions/checkout@v4 + + - name: Setup Python & Poetry Environment + uses: ./.github/actions/python-environment + + - name: Run Distribution Check + run: poetry run -- nox -s lint:build-packages + Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix , Build-Packages] runs-on: ubuntu-24.04 permissions: contents: read @@ -191,19 +207,3 @@ jobs: name: coverage-python${{ matrix.python-version }}-fast path: .coverage include-hidden-files: true - - Build-Packages: - name: Build Package Check - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Tests ] - runs-on: ubuntu-24.04 - permissions: - contents: read - steps: - - name: SCM Checkout - uses: actions/checkout@v4 - - - name: Setup Python & Poetry Environment - uses: ./.github/actions/python-environment - - - name: Run Distribution Check - run: poetry run -- nox -s lint:build-packages diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index cc33c5517..931629b82 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -29,4 +29,4 @@ PROJECT_CONFIG = Config(python_versions=(...), exasol_versions=(...), create_maj * #465: Created BaseConfig class to better synchronize attributes needed for the PTB's growing functionalities -* #494: Created check of built packages +* #494: Created check of built packages with nox session ``package:check``: diff --git a/exasol/toolbox/nox/_lint.py b/exasol/toolbox/nox/_lint.py index ef9de82dc..890839a10 100644 --- a/exasol/toolbox/nox/_lint.py +++ b/exasol/toolbox/nox/_lint.py @@ -177,13 +177,3 @@ def import_lint(session: Session) -> None: "Please make sure you have a configuration file for the importlinter" ) _import_lint(session=session, path=path) - - -@nox.session(name="lint:build-packages", python=False) -def dist_check(session: Session) -> None: - """Checks whether your distribution’s long description will render correctly on PyPI - - This has more robust checks for rst documentation than markdown. - """ - session.run("poetry", "build", "--project", PROJECT_CONFIG.root) - session.run("twine", "check", PROJECT_CONFIG.root / "./dist/*") diff --git a/exasol/toolbox/nox/_package.py b/exasol/toolbox/nox/_package.py new file mode 100644 index 000000000..12996f715 --- /dev/null +++ b/exasol/toolbox/nox/_package.py @@ -0,0 +1,16 @@ +from __future__ import annotations + +import nox +from nox import Session + +from noxconfig import PROJECT_CONFIG + + +@nox.session(name="package:check", python=False) +def package_check(session: Session) -> None: + """Checks whether your distribution’s long description will render correctly on PyPI + + This has more robust checks for rst documentation than markdown. + """ + session.run("poetry", "build", "--project", PROJECT_CONFIG.root) + session.run("twine", "check", PROJECT_CONFIG.root / "./dist/*") diff --git a/exasol/toolbox/nox/tasks.py b/exasol/toolbox/nox/tasks.py index b99127dac..d9ed6dc51 100644 --- a/exasol/toolbox/nox/tasks.py +++ b/exasol/toolbox/nox/tasks.py @@ -88,5 +88,7 @@ def check(session: Session) -> None: from exasol.toolbox.nox._package_version import version_check +from exasol.toolbox.nox._package import package_check + # isort: on # fmt: on diff --git a/exasol/toolbox/templates/github/workflows/checks.yml b/exasol/toolbox/templates/github/workflows/checks.yml index b8556d915..ce3069d3b 100644 --- a/exasol/toolbox/templates/github/workflows/checks.yml +++ b/exasol/toolbox/templates/github/workflows/checks.yml @@ -160,9 +160,25 @@ jobs: - name: Run format check run: poetry run -- nox -s project:format + Build-Packages: + name: Build Package Check + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + runs-on: ubuntu-24.04 + permissions: + contents: read + steps: + - name: SCM Checkout + uses: actions/checkout@v4 + + - name: Setup Python & Poetry Environment + uses: exasol/python-toolbox/.github/actions/python-environment@v1 + + - name: Run Distribution Check + run: poetry run -- nox -s lint:build-packages + Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Build-Packages ] runs-on: ubuntu-24.04 permissions: contents: read @@ -188,19 +204,3 @@ jobs: name: coverage-python${{ matrix.python-version }}-fast path: .coverage include-hidden-files: true - - Build-Packages: - name: Build Package Check - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Tests ] - runs-on: ubuntu-24.04 - permissions: - contents: read - steps: - - name: SCM Checkout - uses: actions/checkout@v4 - - - name: Setup Python & Poetry Environment - uses: ./.github/actions/python-environment - - - name: Run Distribution Check - run: poetry run -- nox -s lint:build-packages diff --git a/test/unit/nox/_lint_test.py b/test/unit/nox/_lint_test.py deleted file mode 100644 index 738a702d4..000000000 --- a/test/unit/nox/_lint_test.py +++ /dev/null @@ -1,23 +0,0 @@ -import pytest -from nox.command import CommandFailed - -from exasol.toolbox.nox._lint import dist_check - - -class TestDistributionCheck: - @staticmethod - def test_works_as_expected(nox_session): - dist_check(nox_session) - - @staticmethod - def test_raises_non_zero_exist_with_readme_error(nox_session): - # TODOs - # 1. copy package files to a temp directory - # 2. mock/alter the path for the function you need to use for testing - # 3. modify rst file to have a broken link like is in this commit: - # - `Python = 3.9 - - with pytest.raises(CommandFailed) as e: - dist_check(nox_session) - # verify broken with non-zero exit status - assert str(e.value) == "Returned code 1" diff --git a/test/unit/nox/_package_check_test.py b/test/unit/nox/_package_check_test.py new file mode 100644 index 000000000..d561a68bb --- /dev/null +++ b/test/unit/nox/_package_check_test.py @@ -0,0 +1,45 @@ +import pytest +from unittest.mock import ( + MagicMock, + patch, +) +from nox.command import CommandFailed +import shutil +from pathlib import Path + +from exasol.toolbox.nox._package import package_check, PROJECT_CONFIG +from exasol.toolbox.config import BaseConfig + +class TestDistributionCheck: + @staticmethod + def test_works_as_expected(nox_session): + package_check(nox_session) + + @staticmethod + def test_raises_non_zero_exist_with_readme_error(nox_session, tmp_path): + # TODOs + # 1. copy package files to a temp directory + # 2. mock/alter the path for the function you need to use for testing + # 3. modify rst file to have a broken link like is in this commit: + # - `Python = 3.9 + package = Path(tmp_path) + package_readme = package / "README.rst" + shutil.copytree(PROJECT_CONFIG.root / "exasol", package / "exasol") + shutil.copyfile(PROJECT_CONFIG.root / "README.rst", package_readme) + shutil.copytree(PROJECT_CONFIG.root / "doc/changes", package / "doc/changes") + shutil.copyfile(PROJECT_CONFIG.root / "LICENSE", package / "LICENSE") + shutil.copyfile(PROJECT_CONFIG.root / "pyproject.toml", package / "pyproject.toml") + old = "- `Python `__ >= 3.9" + error = "- `Python `__ >= 3.9" + readme = package_readme.read_text().splitlines() + error_readme = [error if old in line else line for line in readme] + package_readme.write_text("/n".join(error_readme)) + config = BaseConfig() + mock = MagicMock(spec=BaseConfig, wraps=config) + mock.root = package + with pytest.raises(CommandFailed) as e: + with patch("exasol.toolbox.nox._package.PROJECT_CONFIG", mock): + print(PROJECT_CONFIG.root) + package_check(nox_session) + # verify broken with non-zero exit status + assert str(e.value) == "Returned code 1" \ No newline at end of file From ed8caae92fdd4f866084e6d0b7fcf1d9a88bc633 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Tue, 30 Sep 2025 12:48:47 +0200 Subject: [PATCH 06/14] Format code --- test/unit/nox/_package_check_test.py | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/test/unit/nox/_package_check_test.py b/test/unit/nox/_package_check_test.py index d561a68bb..b809ac22d 100644 --- a/test/unit/nox/_package_check_test.py +++ b/test/unit/nox/_package_check_test.py @@ -1,14 +1,19 @@ -import pytest +import shutil +from pathlib import Path from unittest.mock import ( MagicMock, patch, ) + +import pytest from nox.command import CommandFailed -import shutil -from pathlib import Path -from exasol.toolbox.nox._package import package_check, PROJECT_CONFIG from exasol.toolbox.config import BaseConfig +from exasol.toolbox.nox._package import ( + PROJECT_CONFIG, + package_check, +) + class TestDistributionCheck: @staticmethod @@ -28,7 +33,9 @@ def test_raises_non_zero_exist_with_readme_error(nox_session, tmp_path): shutil.copyfile(PROJECT_CONFIG.root / "README.rst", package_readme) shutil.copytree(PROJECT_CONFIG.root / "doc/changes", package / "doc/changes") shutil.copyfile(PROJECT_CONFIG.root / "LICENSE", package / "LICENSE") - shutil.copyfile(PROJECT_CONFIG.root / "pyproject.toml", package / "pyproject.toml") + shutil.copyfile( + PROJECT_CONFIG.root / "pyproject.toml", package / "pyproject.toml" + ) old = "- `Python `__ >= 3.9" error = "- `Python `__ >= 3.9" readme = package_readme.read_text().splitlines() @@ -42,4 +49,4 @@ def test_raises_non_zero_exist_with_readme_error(nox_session, tmp_path): print(PROJECT_CONFIG.root) package_check(nox_session) # verify broken with non-zero exit status - assert str(e.value) == "Returned code 1" \ No newline at end of file + assert str(e.value) == "Returned code 1" From a847286d0783726e8a97e5f99997223d93457749 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Tue, 30 Sep 2025 12:49:01 +0200 Subject: [PATCH 07/14] Remove formatting error introduced for demo purposes --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index c93731d15..f95165566 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,7 @@ Your one-stop solution for managing all standard tasks and core workflows of you 🔌️ Prerequisites ----------------- -- `Python = 3.9 +- `Python `__ >= 3.9 💾 Installation --------------- From 489140333395cc2e9c97b67f127e1ca6430a3890 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Tue, 30 Sep 2025 17:48:00 +0200 Subject: [PATCH 08/14] resolve conversation --- .github/workflows/checks.yml | 6 +-- README.rst | 2 +- doc/changes/unreleased.md | 2 +- .../templates/github/workflows/checks.yml | 6 +-- test/unit/nox/_package_check_test.py | 37 +++++++++++-------- 5 files changed, 29 insertions(+), 24 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index a5b5ccdd2..1ccb49b25 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -162,7 +162,7 @@ jobs: Build-Packages: name: Build Package Check - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + needs: [ Documentation, Lint, Type-Check, Security, Format ] runs-on: ubuntu-24.04 permissions: contents: read @@ -174,11 +174,11 @@ jobs: uses: ./.github/actions/python-environment - name: Run Distribution Check - run: poetry run -- nox -s lint:build-packages + run: poetry run -- nox -s package:check Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix , Build-Packages] + needs: [ Build-Packages ] runs-on: ubuntu-24.04 permissions: contents: read diff --git a/README.rst b/README.rst index c93731d15..f95165566 100644 --- a/README.rst +++ b/README.rst @@ -47,7 +47,7 @@ Your one-stop solution for managing all standard tasks and core workflows of you 🔌️ Prerequisites ----------------- -- `Python = 3.9 +- `Python `__ >= 3.9 💾 Installation --------------- diff --git a/doc/changes/unreleased.md b/doc/changes/unreleased.md index 931629b82..9990769f7 100644 --- a/doc/changes/unreleased.md +++ b/doc/changes/unreleased.md @@ -29,4 +29,4 @@ PROJECT_CONFIG = Config(python_versions=(...), exasol_versions=(...), create_maj * #465: Created BaseConfig class to better synchronize attributes needed for the PTB's growing functionalities -* #494: Created check of built packages with nox session ``package:check``: +* #494: Created check of built packages with nox session `package:check` diff --git a/exasol/toolbox/templates/github/workflows/checks.yml b/exasol/toolbox/templates/github/workflows/checks.yml index ce3069d3b..ea991b08b 100644 --- a/exasol/toolbox/templates/github/workflows/checks.yml +++ b/exasol/toolbox/templates/github/workflows/checks.yml @@ -162,7 +162,7 @@ jobs: Build-Packages: name: Build Package Check - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix ] + needs: [ Documentation, Lint, Type-Check, Security, Format ] runs-on: ubuntu-24.04 permissions: contents: read @@ -174,11 +174,11 @@ jobs: uses: exasol/python-toolbox/.github/actions/python-environment@v1 - name: Run Distribution Check - run: poetry run -- nox -s lint:build-packages + run: poetry run -- nox -s package:check Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Documentation, Lint, Type-Check, Security, Format, build-matrix, Build-Packages ] + needs: [ Build-Packages ] runs-on: ubuntu-24.04 permissions: contents: read diff --git a/test/unit/nox/_package_check_test.py b/test/unit/nox/_package_check_test.py index d561a68bb..393359a8a 100644 --- a/test/unit/nox/_package_check_test.py +++ b/test/unit/nox/_package_check_test.py @@ -1,14 +1,19 @@ -import pytest +import shutil +from pathlib import Path from unittest.mock import ( MagicMock, patch, ) + +import pytest from nox.command import CommandFailed -import shutil -from pathlib import Path -from exasol.toolbox.nox._package import package_check, PROJECT_CONFIG from exasol.toolbox.config import BaseConfig +from exasol.toolbox.nox._package import ( + PROJECT_CONFIG, + package_check, +) + class TestDistributionCheck: @staticmethod @@ -17,23 +22,23 @@ def test_works_as_expected(nox_session): @staticmethod def test_raises_non_zero_exist_with_readme_error(nox_session, tmp_path): - # TODOs - # 1. copy package files to a temp directory - # 2. mock/alter the path for the function you need to use for testing - # 3. modify rst file to have a broken link like is in this commit: - # - `Python = 3.9 package = Path(tmp_path) package_readme = package / "README.rst" + + # copy over `packages` and `include` from `pyproject.toml` to for `poetry build` shutil.copytree(PROJECT_CONFIG.root / "exasol", package / "exasol") shutil.copyfile(PROJECT_CONFIG.root / "README.rst", package_readme) shutil.copytree(PROJECT_CONFIG.root / "doc/changes", package / "doc/changes") shutil.copyfile(PROJECT_CONFIG.root / "LICENSE", package / "LICENSE") - shutil.copyfile(PROJECT_CONFIG.root / "pyproject.toml", package / "pyproject.toml") - old = "- `Python `__ >= 3.9" - error = "- `Python `__ >= 3.9" - readme = package_readme.read_text().splitlines() - error_readme = [error if old in line else line for line in readme] - package_readme.write_text("/n".join(error_readme)) + shutil.copyfile( + PROJECT_CONFIG.root / "pyproject.toml", package / "pyproject.toml" + ) + + # create an error in readme.rst + not_closed_link_error = "- `Python = 3.9" + package_readme.open(mode="a").write(not_closed_link_error) + + # use of the folder with errors in the nox -s package:check function config = BaseConfig() mock = MagicMock(spec=BaseConfig, wraps=config) mock.root = package @@ -42,4 +47,4 @@ def test_raises_non_zero_exist_with_readme_error(nox_session, tmp_path): print(PROJECT_CONFIG.root) package_check(nox_session) # verify broken with non-zero exit status - assert str(e.value) == "Returned code 1" \ No newline at end of file + assert str(e.value) == "Returned code 1" From af7db3d168a6ebd25ae76023f4b41d701da0d6fd Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Tue, 30 Sep 2025 18:07:20 +0200 Subject: [PATCH 09/14] fix --- doc/user_guide/features/metrics/collecting_metrics.rst | 2 +- doc/user_guide/features/metrics/sonar.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/user_guide/features/metrics/collecting_metrics.rst b/doc/user_guide/features/metrics/collecting_metrics.rst index b133a8ffa..179efc3ac 100644 --- a/doc/user_guide/features/metrics/collecting_metrics.rst +++ b/doc/user_guide/features/metrics/collecting_metrics.rst @@ -56,7 +56,7 @@ into a report: #. SonarQube analysis This summarization tool feeds into a feature-rich UI provided by - `Sonar `__. For further + `Sonar `__. For further details, see :ref:`sonarqube_analysis` Both of these reporting options require that the generated files from the :ref:`generated_metrics` diff --git a/doc/user_guide/features/metrics/sonar.rst b/doc/user_guide/features/metrics/sonar.rst index a48e4a337..696353a8a 100644 --- a/doc/user_guide/features/metrics/sonar.rst +++ b/doc/user_guide/features/metrics/sonar.rst @@ -3,7 +3,7 @@ SonarQube analysis ================== -The PTB supports using `SonarQube Cloud `__ +The PTB supports using `SonarQube Cloud `__ to analyze, visualize, & track linting, security, & coverage. All of our Python projects should be evaluated against the `Exasol Way`_ and subscribe to the `Clean as You Code `__ From 1be8f3cae9bb940f4efd13ae2c385200e811abd1 Mon Sep 17 00:00:00 2001 From: Ariel Schulz Date: Tue, 30 Sep 2025 20:51:20 +0200 Subject: [PATCH 10/14] Reviewer error: need build-matrix for unit test --- .github/workflows/checks.yml | 2 +- exasol/toolbox/templates/github/workflows/checks.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/checks.yml b/.github/workflows/checks.yml index 1ccb49b25..54262ca8f 100644 --- a/.github/workflows/checks.yml +++ b/.github/workflows/checks.yml @@ -178,7 +178,7 @@ jobs: Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Build-Packages ] + needs: [ Build-Packages, build-matrix ] runs-on: ubuntu-24.04 permissions: contents: read diff --git a/exasol/toolbox/templates/github/workflows/checks.yml b/exasol/toolbox/templates/github/workflows/checks.yml index ea991b08b..25937f427 100644 --- a/exasol/toolbox/templates/github/workflows/checks.yml +++ b/exasol/toolbox/templates/github/workflows/checks.yml @@ -178,7 +178,7 @@ jobs: Tests: name: Unit-Tests (Python-${{ matrix.python-version }}) - needs: [ Build-Packages ] + needs: [ Build-Packages, build-matrix ] runs-on: ubuntu-24.04 permissions: contents: read From ecba04506ba55b791294218b758c39b0b3003b33 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Fri, 10 Oct 2025 09:47:40 +0200 Subject: [PATCH 11/14] resolve conversation --- .../{{cookiecutter.repo_name}}/{README.md => README.rst} | 0 project-template/{{cookiecutter.repo_name}}/pyproject.toml | 2 +- test/integration/project-template/nox_test.py | 6 ++++++ 3 files changed, 7 insertions(+), 1 deletion(-) rename project-template/{{cookiecutter.repo_name}}/{README.md => README.rst} (100%) diff --git a/project-template/{{cookiecutter.repo_name}}/README.md b/project-template/{{cookiecutter.repo_name}}/README.rst similarity index 100% rename from project-template/{{cookiecutter.repo_name}}/README.md rename to project-template/{{cookiecutter.repo_name}}/README.rst diff --git a/project-template/{{cookiecutter.repo_name}}/pyproject.toml b/project-template/{{cookiecutter.repo_name}}/pyproject.toml index 3cc266aef..9f6e8f0d6 100644 --- a/project-template/{{cookiecutter.repo_name}}/pyproject.toml +++ b/project-template/{{cookiecutter.repo_name}}/pyproject.toml @@ -6,7 +6,7 @@ description = "{{cookiecutter.description}}" authors = [ {name = "{{cookiecutter.author_full_name}}", email = "{{cookiecutter.author_email}}"}, ] -readme = "README.md" +readme = "README.rst" license = "MIT" keywords = ['exasol', '{{cookiecutter.package_name}}'] dynamic = ["dependencies"] diff --git a/test/integration/project-template/nox_test.py b/test/integration/project-template/nox_test.py index d28852ee6..19210a14e 100644 --- a/test/integration/project-template/nox_test.py +++ b/test/integration/project-template/nox_test.py @@ -52,3 +52,9 @@ def test_artifact_validate(self, poetry_path, run_command): output = run_command(artifacts_validate, check=False) assert output.returncode == 0 + + def test_package_check(self, poetry_path, run_command): + package_check = self._command(poetry_path, "package:check") + output = run_command(package_check) + + assert output.returncode == 0 From 48ecc1f639c9fcf365103a05320c436a23433039 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Fri, 17 Oct 2025 10:57:08 +0200 Subject: [PATCH 12/14] resolve conversation --- .../{{cookiecutter.repo_name}}/README.rst | 52 ++++++++++--------- 1 file changed, 28 insertions(+), 24 deletions(-) diff --git a/project-template/{{cookiecutter.repo_name}}/README.rst b/project-template/{{cookiecutter.repo_name}}/README.rst index e1c3f1597..725db3657 100644 --- a/project-template/{{cookiecutter.repo_name}}/README.rst +++ b/project-template/{{cookiecutter.repo_name}}/README.rst @@ -1,37 +1,41 @@ -

{{cookiecutter.repo_name}}

+{{cookiecutter.repo_name}} +{{ "=" * cookiecutter.repo_name|length }} -

{{cookiecutter.description}} -

-

+.. image:: https://img.shields.io/pypi/l/{{cookiecutter.__repo_name_slug}} + :target: https://opensource.org/licenses/MIT + :alt: License - - License - - - Downloads - - - Supported Python Versions - - - PyPi Package - -

+.. image:: https://img.shields.io/pypi/dm/{{cookiecutter.__repo_name_slug}} + :target: https://pypi.org/project/{{cookiecutter.__repo_name_slug}}/ + :alt: Downloads -## 🚀 Features +.. image:: https://img.shields.io/pypi/pyversions/{{cookiecutter.__repo_name_slug}} + :target: https://pypi.org/project/{{cookiecutter.__repo_name_slug}}/ + :alt: Supported Python Versions -## 🔌️ Prerequisites +.. image:: https://img.shields.io/pypi/v/{{cookiecutter.__repo_name_slug}} + :target: https://pypi.org/project/{{cookiecutter.__repo_name_slug}}/ + :alt: PyPi Package + +🚀 Features +----------- + +🔌️ Prerequisites +---------------- - [Python](https://www.python.org/) >= 3.9 -## 💾 Installation +💾 Installation +--------------- + +.. code-block:: shell + + pip install {{cookiecutter.pypi_package_name}} -```shell -pip install {{cookiecutter.pypi_package_name}} -``` ## 📚 Documentation +------------------- -For futher details, checkout the latest [documentation](https://exasol.github.io/{{cookiecutter.repo_name}}/). +For futher details, checkout the latest `documentation `_. From 16836ed8507c7573296d77703c635d39ba005069 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Fri, 17 Oct 2025 11:43:09 +0200 Subject: [PATCH 13/14] resolve conversation --- project-template/{{cookiecutter.repo_name}}/README.rst | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/project-template/{{cookiecutter.repo_name}}/README.rst b/project-template/{{cookiecutter.repo_name}}/README.rst index 725db3657..68c32adfb 100644 --- a/project-template/{{cookiecutter.repo_name}}/README.rst +++ b/project-template/{{cookiecutter.repo_name}}/README.rst @@ -25,7 +25,7 @@ 🔌️ Prerequisites ---------------- -- [Python](https://www.python.org/) >= 3.9 +- `Python `__ >= 3.9 💾 Installation --------------- @@ -35,7 +35,7 @@ pip install {{cookiecutter.pypi_package_name}} -## 📚 Documentation -------------------- +📚 Documentation +---------------- -For futher details, checkout the latest `documentation `_. +For futher details, checkout the latest `documentation `__. From 58139be973a8ea6fa51679cf026d23824cf2c3c4 Mon Sep 17 00:00:00 2001 From: Jannis Mittenzwei Date: Fri, 17 Oct 2025 11:54:21 +0200 Subject: [PATCH 14/14] resolve conversation --- project-template/{{cookiecutter.repo_name}}/README.rst | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/project-template/{{cookiecutter.repo_name}}/README.rst b/project-template/{{cookiecutter.repo_name}}/README.rst index 68c32adfb..9a4a15a63 100644 --- a/project-template/{{cookiecutter.repo_name}}/README.rst +++ b/project-template/{{cookiecutter.repo_name}}/README.rst @@ -23,7 +23,7 @@ ----------- 🔌️ Prerequisites ----------------- +----------------- - `Python `__ >= 3.9 @@ -34,8 +34,7 @@ pip install {{cookiecutter.pypi_package_name}} - 📚 Documentation ---------------- -For futher details, checkout the latest `documentation `__. +For further details, check out the latest `documentation `_. \ No newline at end of file