diff --git a/.github/actions/features_parse/action.yml b/.github/actions/features_parse/action.yml deleted file mode 100644 index 99c79a2f..00000000 --- a/.github/actions/features_parse/action.yml +++ /dev/null @@ -1,18 +0,0 @@ -name: features_parse -description: Parses the given GardenLinux features parameters -inputs: - flags: - description: "Flags passed to `gl-features-parse`" - required: true -outputs: - result: - description: "features result" - value: ${{ steps.result.outputs.result }} -runs: - using: composite - steps: - - uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.10.11 - - id: result - shell: bash - run: | - echo "result=$(gl-features-parse ${{ inputs.flags }})" | tee -a $GITHUB_OUTPUT diff --git a/.github/actions/flavors_parse/action.yml b/.github/actions/flavors_parse/action.yml deleted file mode 100644 index b31b58a2..00000000 --- a/.github/actions/flavors_parse/action.yml +++ /dev/null @@ -1,34 +0,0 @@ -name: flavors_parse -description: Parses the given GardenLinux flavors parameters -inputs: - flags: - description: "Flags passed to `gl-flavors-parse`" - required: true - flavors_matrix: - description: "Generated GitHub workflow flavors matrix" -outputs: - matrix: - description: "Flavors matrix" - value: ${{ steps.matrix.outputs.matrix }} -runs: - using: composite - steps: - - uses: gardenlinux/python-gardenlinux-lib/.github/actions/setup@0.10.11 - - id: matrix - shell: bash - run: | - MATRIX='${{ inputs.flavors_matrix }}' - - if [[ $(echo "${MATRIX}" | jq -r 'type') != 'object' ]]; then - FLAVORS=$(gl-flavors-parse ${{ inputs.flags }}) - MATRIX=$(jq -nc \ - --argjson flavors "$(echo $FLAVORS)" \ - '{ - include: ( - $flavors | reduce (to_entries[]) as $item ([]; . + ($item.value | map({"arch": $item.key, "flavor": .}))) - ) - }' - ) - fi - - echo "matrix=$MATRIX" | tee -a $GITHUB_OUTPUT diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index ea1dcf0b..834f774f 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,7 +2,10 @@ name: pre-release on: push: - tags: [ "[0-9]+.[0-9]+.[0-9]+*" ] + branches: + - main + tags: + - "[0-9]+.[0-9]+.[0-9]+*" env: GIT_CLIFF_VERSION: 2.13.1 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cb783c5c..984bb12e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -22,6 +22,5 @@ repos: - id: mypy args: [--strict, --ignore-missing-imports, --check-untyped-defs, --allow-untyped-decorators] additional_dependencies: - - types-click - types-PyYAML - types-requests diff --git a/cliff.toml b/cliff.toml index 4199d166..b6aff8c1 100644 --- a/cliff.toml +++ b/cliff.toml @@ -42,11 +42,10 @@ footer = """ {% for release in releases -%} {% if release.version -%} {% if release.previous.version -%} - [{{ release.previous.version | trim_start_matches(pat="v") }}]: \ - {{ self::remote_url() }}/compare/{{ release.previous.version }}...{{ release.version }} + - [v{{ release.previous.version | trim_start_matches(pat="v") }}]({{ self::remote_url() }}/compare/{{ release.previous.version }}...{{ release.version }}) {% endif -%} {% else -%} - [unreleased]: {{ self::remote_url() }}/compare/{{ release.previous.version }}...HEAD + - [unreleased]({{ self::remote_url() }}/compare/{{ release.previous.version }}...HEAD) {% endif -%} {% endfor %} diff --git a/docs/cli.rst b/docs/cli.rst index f975b2aa..caee3ff5 100644 --- a/docs/cli.rst +++ b/docs/cli.rst @@ -6,20 +6,20 @@ Available command-line tools provided by the Garden Linux Python Library Features Commands ----------------- -gl-cname -~~~~~~~~ - -Generate a canonical name (cname) from feature sets. - -.. autoprogram:: gardenlinux.features.cname_main:get_parser() - gl-features-parse ~~~~~~~~~~~~~~~~~ -Parse and extract information from GardenLinux features. +Parse and extract information from Garden Linux features. .. autoprogram:: gardenlinux.features.__main__:get_parser() +gl-features-metadata +~~~~~~~~~~~~~~~~~~~~ + +Provides Garden Linux release metadata file handling. + +.. autoprogram:: gardenlinux.features.metadata_main:get_parser() + Flavors Commands ---------------- @@ -38,9 +38,7 @@ gl-oci Push OCI artifacts to a registry and manage manifests. -.. click:: gardenlinux.oci.__main__:cli - :prog: gl-oci - :show-nested: +.. autoprogram:: gardenlinux.oci.__main__:get_parser() S3 Commands ----------- diff --git a/docs/conf.py b/docs/conf.py index a24c6f5f..45b219c5 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -20,7 +20,6 @@ "sphinx.ext.coverage", "sphinx_rtd_theme", "sphinx.ext.napoleon", - "sphinx_click", "sphinxcontrib.autoprogram", "sphinx_markdown_builder", ] diff --git a/poetry.lock b/poetry.lock index d29211c2..5f36c432 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 2.4.1 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.2.0 and should not be changed by hand. [[package]] name = "alabaster" @@ -25,45 +25,69 @@ files = [ [[package]] name = "ast-serialize" -version = "0.5.0" +version = "0.12.1" description = "Python bindings for mypy AST serialization" optional = false python-versions = ">=3.7" groups = ["dev"] files = [ - {file = "ast_serialize-0.5.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:8f5c14f169eb0972c0c21bada5358b23d6047c76583b005234f865b11f1fa00a"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7d1a2de9de5be04652f0ed60738356ef94f66db37924a9499fffe98dc491aa0b"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be5173fb66f9b49026d9d5a2ff0fc7c7009077107c0eb285b2d60fdf1fe10bd1"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f8015cd071ac1339924ee2b8098c93e00e155f30a16f40ec9816fcf84f4753f6"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5499e8797edff2a9186aa313ed382c6b422e798e9332d9953badcee6e69a88f2"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6848f2a093fb5548751a9a09bff8fcd229e2bbeb0e3331f391b6ae6d26cd9903"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:832d4c998e0b091fd60a6d6bceee535483c4d490de9ba85003af835225719261"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:16db7c62ec0b8efe1d7afd283a388d8f74f2605d56032e5a37747d2de8dba027"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:baf5eb061eb5bccade4128ad42da33787d72f6013809cd1b590376ece8b3c937"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:104e4a35bd7c124173c41760ef9aaea17ddb3f86c65cb643671d59afbe3ee94c"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:36be371028fc1675acb38a331bde160dbab7ff907fdf00b67eb6911aa106951b"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:061ee58bdb52341c8201a6df41182a977736bae3b7ded87ca7176ca25a8a47ab"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b15219e9cdc9f53f6f4cb51c009203507228226148c05c5e8fe451c28b435eb3"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-win32.whl", hash = "sha256:842d1c004bb466c7df036f95fabef789570541922b10976b12f5592a69cf0b38"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-win_amd64.whl", hash = "sha256:b0c06d760909b095cc466356dfccd05a1c7233a6ca191c020dca2c6a6f16c24c"}, - {file = "ast_serialize-0.5.0-cp314-cp314t-win_arm64.whl", hash = "sha256:787baedb0262cc49e8ce37cc15c00ae818e46a165a3b36f5e21ed174998104cb"}, - {file = "ast_serialize-0.5.0-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:0668aa9459cfa8c9c49ddd2163ebcf43088ba045ef7492af6fe22e0098303101"}, - {file = "ast_serialize-0.5.0-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:bf683d6363edf2b39eed6b6d4fe22d34b6203867a67e27134d9e2a2680c4bc4a"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9cc22cf0c9be65e71cf88fda130af60d61eb4a79370ad4cfe7900d48a4aa2211"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f66173891548c9f2726bf27957b41cabce12fa679dc6da505ddbde4d4b3b31cf"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e42d729ef2be96a14efbad355093284739e3670ece3e534f82cc8832790911d9"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b725026bafa801dbd7310eb13a75f0a2e370e7e51b2cb225f9d21fcfadf919ee"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b54f60c1d78767a53b67eaa663f0dfac3afe606aa07f1301572f588b73d64809"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:27d51654fc240a1e87e742d353d98eb45b75f62f129086b3596ab53df2ac2a43"}, - {file = "ast_serialize-0.5.0-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2782c36237c46dd1674542f2109740ea5ea485a169bf1431939ada0434e17934"}, - {file = "ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1943db345233cc7194a470f13afa9c59772c0b123dea0c9414c4d4ca54369759"}, - {file = "ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:df1c00022cbbcb064bfaa505aa9c9295362443ce5dacb459d1331d3da353f887"}, - {file = "ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:cae65289fc456fde04af979a2be09302ef5d8ab92ef23e596d6746dc267ada27"}, - {file = "ast_serialize-0.5.0-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:239a4c354e8d676e9d94631d1d4a64edc6b266f86ff3a5a80aedd344f342c01d"}, - {file = "ast_serialize-0.5.0-cp39-abi3-win32.whl", hash = "sha256:143a4ef63285a075871908fda3672dc21864b83a8ec3ee12304aa3e4c5387b9a"}, - {file = "ast_serialize-0.5.0-cp39-abi3-win_amd64.whl", hash = "sha256:cf25572c526add400f26a4750dc6ce0c3bb93fc1f75e7ae0cad4ce4f2cd5c590"}, - {file = "ast_serialize-0.5.0-cp39-abi3-win_arm64.whl", hash = "sha256:92a31c9c20d25a076edaeec76b128a3535d74a24f340b9a8a7e96c9b86dc9642"}, - {file = "ast_serialize-0.5.0.tar.gz", hash = "sha256:5880091bfe6f4f986f22866375c2e884843e7a0b6343ae41aeea659613d879b6"}, + {file = "ast_serialize-0.12.1-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:e73255c9227fd74eac8a9b55c4049e8ad7b66d1f690bf827c98a86b2e594def7"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:4655ef993e69e01bb47d2d99647de9bbb74af03938438656832cd010d95de348"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:bac5a99a2c91dd823be9b8c44645694fccbb0750773cc5b27889a9f6f22fce89"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6485e681625ed7a094221f16a7ff2ef154946112266a05cf83bde50c959ef345"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a513bc6f60980d01767f7cbe39b17ce0373e722824a74ce28d6cea49ee3c8460"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:82866f3523d53ffca8d2a69a750bec52908b69f728012e40959bebce2620453c"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:243054a05a5190f5d087b5c8b16423e7f1cefa4991bac26e9c8ace18074b75b6"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7d9fbe5a3e8acddfc2fddff3dbbc7ea0e9798b3df3428f851b8abc52a3806f31"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:d3d516da3463071d27e64caf54d88cba25cf4ad4afcc807e0bcf67743719f03e"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d6711adf11136c77e3a35517de9488a5081d1012874fae99c2876b64f4daace"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:cbe239bee4bd609186daf60b95b7b0f47146c7f7f55f6da83807d747d6fe753f"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:5bbf582286c9dc6b4c544ef645dc99e4b3aa09db28892bc60344141f6926641f"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:99e33c93efb5254a70c525b46038212371dfe5693d48eb2d0d5f17d936a263d7"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:aa6c17a2b7f07e81fa8cfcc4aa7c832b3e57733853aebea113ab502f9b0963db"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f896fa38e0af38821e1ab1425c5dee89e359623e165765bdeae7d0eb6909e76d"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:af699e81fd7ce80b8b03945826d8ea23dd36d072f10d4613402da597ba4ee9c6"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-win32.whl", hash = "sha256:10b59afc108eb285146acb23d1b5ec0fc58bb3c09cb2ab8876402df06c373c3b"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-win_amd64.whl", hash = "sha256:72e871f6995a066c1b19104f8a6b5832b1163adb9a8267c2aa4711fbb0f4d1f3"}, + {file = "ast_serialize-0.12.1-cp314-cp314t-win_arm64.whl", hash = "sha256:3398e458047d21c9bc1b323fe5aab77c608dc9ddb65b2d44deebaff503a1f1eb"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-macosx_10_12_x86_64.whl", hash = "sha256:410233de149ab8414cb27c6fc73e9d2baa35d6f971672d540d752060d980ffb4"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-macosx_11_0_arm64.whl", hash = "sha256:b9a2310845302f1a6bd45ae8a67d5760211103a8d66410b854bfa440d107e093"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6ff65f40f49d5e1a1a043ba366081d59a4e26a9f5c1b07eb1170e172115da7ca"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:536d783c4d91331f094e0a892221e619be5ffbe6fb6640885f14d7f226ec90ca"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c42d2d65f388d1960c5796231eb9bf5a988c46228633eb489605c4549ad16c52"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a5628a12acc875fe7a167910f18d101dd101c2a7b1e6c2b6f7289ffaff25805c"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e855adfa5bb982b2e6fe09056b2d584f6dd4fce085d91a07d1155683751b6b5"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_31_riscv64.whl", hash = "sha256:fafe1471e8aca6c87b4913b7b54ff97197adf702fbe28692284b929dfa62ff96"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a5cac246474d2a703147d1605a6ac5ba0fa9e0a443cf1cf42513adf4df02686f"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_aarch64.whl", hash = "sha256:6e25cd319fb0d7b39fcac666784ec86708ccbc78d07a698b1400cf5ed40c045b"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_armv7l.whl", hash = "sha256:657a7354ea16ed4d29f8127ed477c6fee3915c111d135f020ca835a991438e90"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_i686.whl", hash = "sha256:9eb9de7e59621acdb3e66984f374272b33d56d15a04763e2fd0604211e1c8303"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_ppc64le.whl", hash = "sha256:09cc4d3103c1fc97f6845ba307af1db9cde5226bef47f8843220dde83f2276ba"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_riscv64.whl", hash = "sha256:c9e2a592706fd791c2271ce9c8f4e38c98d3ea0b4a86b511e09a4fe3ac44ab37"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-musllinux_1_2_x86_64.whl", hash = "sha256:f4ac042e95a575432c1730ca4cb9183066a2074886a599f46c1f1b0955fb8198"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-win32.whl", hash = "sha256:b3cd105995942cc6163a229674a86161ba1305f646493efd59bd6723a357ee14"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-win_amd64.whl", hash = "sha256:a9cd24a26126088693ca054547ea0a391398a29cf1a3a2bec1009b4b6acc8b82"}, + {file = "ast_serialize-0.12.1-cp315-abi3.abi3t-win_arm64.whl", hash = "sha256:9649cd903db0dc047906c6dd740784a2ba665d54f7e43ba31457edbce76c9493"}, + {file = "ast_serialize-0.12.1-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:5ef62601db3ce5c23445132262a193075e211fb2fc87b46b7550dd351fac0976"}, + {file = "ast_serialize-0.12.1-cp39-abi3-macosx_10_12_x86_64.whl", hash = "sha256:98d91cd3a6cb76a39512ee090a539d1e3206b732ad8150eb38918cffa1ddf515"}, + {file = "ast_serialize-0.12.1-cp39-abi3-macosx_11_0_arm64.whl", hash = "sha256:8a32f184ce3e4b1d0b06d642a1243281cf55b99e0323680b1b8f904029fd7700"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e62126ac2be2d9340ac1b3ee7a0466a883ecbed634cff0929c88ca0b671483b7"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0f93a70fa9826c04ea9f2c3a880f87f4cca09a828144ed5084682abd28110980"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1858887be56a64a2aea899423dfe43787c34c75c18b0d7497de8e618d54b2790"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:89a2bc39a820bc7785b60c53a5742b4e8dd4c1a599294e2dd68fae545883d44a"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:50a9eaedf1db4857dad7cc47dd757ed70bfcc40b89d44d516c4a2f0d5033bd76"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_31_riscv64.whl", hash = "sha256:c30b609e8fea426b310543126de876592236a25aa8ebd59f1e2b323dd52a4085"}, + {file = "ast_serialize-0.12.1-cp39-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:7b1ad06513022cfa1337744959255af0ef16119d2beb1e547b67f37ad9433d4a"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6add54b495e37ae3cf3a1f0d5eaba364814eb72e93026adc41b7791e4b0d45d3"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:5fc136cd08001b817ad0b3e7426f50a7d2b8982dc7c6491f0af78af4c3dd8672"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_i686.whl", hash = "sha256:45a9e6b700bbd973d49942668a5cdbeffa693f2e250b8a5409abd1fa9d351854"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:a1d8267f83c613ea0a31f2518df074bd62e98a4b3a4892f6a529d74e08e02dba"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:9a0cbab9796e6ce841197feeba4008faa96b4cc7741129542fd81c882d7a4f01"}, + {file = "ast_serialize-0.12.1-cp39-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b4282695f1d51a3c6ef76560351bad5af880eff7d755aefea325bffb9bf68c25"}, + {file = "ast_serialize-0.12.1-cp39-abi3-win32.whl", hash = "sha256:119d1b0cadaba4a6e475f9bbe79eecc79351e373142eabe7c353f0250d70aebb"}, + {file = "ast_serialize-0.12.1-cp39-abi3-win_amd64.whl", hash = "sha256:3d6ed63d4fc1ec867b8cb522d58c36df0e8f05e487bea0ffd102043a37636d72"}, + {file = "ast_serialize-0.12.1-cp39-abi3-win_arm64.whl", hash = "sha256:610a41351de68199de9a1434499083b4256c0df7658ec1cfc0a0a7b20b08d317"}, + {file = "ast_serialize-0.12.1.tar.gz", hash = "sha256:5285a390caf1c44368ae270f037f797b91427d138b7d43cad0f1fda4c83518d9"}, ] [[package]] @@ -120,18 +144,18 @@ yaml = ["PyYAML"] [[package]] name = "boto3" -version = "1.43.36" -description = "The AWS SDK for Python" +version = "1.43.108" +description = "The AWS SDK for Python (Boto3)" optional = false python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "boto3-1.43.36-py3-none-any.whl", hash = "sha256:42942dde254673abcbc9e6e60017c88341a4f49d99d24e1f2e290fb38138c26f"}, - {file = "boto3-1.43.36.tar.gz", hash = "sha256:587d7ee92a12e440ad12b0e7f11f3358f0c4d65b19f64726efc94aaf194aff28"}, + {file = "boto3-1.43.108-py3-none-any.whl", hash = "sha256:19e9da95ef0c494e27052049a42137550e66730509bb613e76eaa30ddf9a7170"}, + {file = "boto3-1.43.108.tar.gz", hash = "sha256:03341f089158368acf83e921aca98b706095322ca52bc4c039a616940aa5ad41"}, ] [package.dependencies] -botocore = ">=1.43.36,<1.44.0" +botocore = ">=1.43.108,<1.44.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.19.0,<0.20.0" @@ -140,14 +164,14 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "boto3-stubs" -version = "1.43.34" -description = "Type annotations for boto3 1.43.34 generated with mypy-boto3-builder 8.12.0" +version = "1.43.108" +description = "Type annotations for boto3 1.43.108 generated with mypy-boto3-builder 8.12.0" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "boto3_stubs-1.43.34-py3-none-any.whl", hash = "sha256:66794a638cf96307622124eaa786f32e3eff7f87b683f1d0d60cf4bc40ce69ae"}, - {file = "boto3_stubs-1.43.34.tar.gz", hash = "sha256:2b6580065e1e145687fd576f15bcf5a399619c8d5121769c8a59c784c2dd22ac"}, + {file = "boto3_stubs-1.43.108-py3-none-any.whl", hash = "sha256:40f02e30f6e455ccb658dcdeb5756ce23bde767f425ab6d7f57a9ffad75a848c"}, + {file = "boto3_stubs-1.43.108.tar.gz", hash = "sha256:a1ed29b4c7957568e6261fc36d4c59025c004997a229e8f01940c205f2128e4a"}, ] [package.dependencies] @@ -158,10 +182,13 @@ types-s3transfer = "*" [package.extras] accessanalyzer = ["mypy-boto3-accessanalyzer (>=1.43.0,<1.44.0)"] account = ["mypy-boto3-account (>=1.43.0,<1.44.0)"] +account-access = ["mypy-boto3-account-access (>=1.43.0,<1.44.0)"] acm = ["mypy-boto3-acm (>=1.43.0,<1.44.0)"] acm-pca = ["mypy-boto3-acm-pca (>=1.43.0,<1.44.0)"] +agent-registry = ["mypy-boto3-agent-registry (>=1.43.0,<1.44.0)"] +agent-registry-control = ["mypy-boto3-agent-registry-control (>=1.43.0,<1.44.0)"] aiops = ["mypy-boto3-aiops (>=1.43.0,<1.44.0)"] -all = ["mypy-boto3-accessanalyzer (>=1.43.0,<1.44.0)", "mypy-boto3-account (>=1.43.0,<1.44.0)", "mypy-boto3-acm (>=1.43.0,<1.44.0)", "mypy-boto3-acm-pca (>=1.43.0,<1.44.0)", "mypy-boto3-aiops (>=1.43.0,<1.44.0)", "mypy-boto3-amp (>=1.43.0,<1.44.0)", "mypy-boto3-amplify (>=1.43.0,<1.44.0)", "mypy-boto3-amplifybackend (>=1.43.0,<1.44.0)", "mypy-boto3-amplifyuibuilder (>=1.43.0,<1.44.0)", "mypy-boto3-apigateway (>=1.43.0,<1.44.0)", "mypy-boto3-apigatewaymanagementapi (>=1.43.0,<1.44.0)", "mypy-boto3-apigatewayv2 (>=1.43.0,<1.44.0)", "mypy-boto3-appconfig (>=1.43.0,<1.44.0)", "mypy-boto3-appconfigdata (>=1.43.0,<1.44.0)", "mypy-boto3-appfabric (>=1.43.0,<1.44.0)", "mypy-boto3-appflow (>=1.43.0,<1.44.0)", "mypy-boto3-appintegrations (>=1.43.0,<1.44.0)", "mypy-boto3-application-autoscaling (>=1.43.0,<1.44.0)", "mypy-boto3-application-insights (>=1.43.0,<1.44.0)", "mypy-boto3-application-signals (>=1.43.0,<1.44.0)", "mypy-boto3-applicationcostprofiler (>=1.43.0,<1.44.0)", "mypy-boto3-appmesh (>=1.43.0,<1.44.0)", "mypy-boto3-apprunner (>=1.43.0,<1.44.0)", "mypy-boto3-appstream (>=1.43.0,<1.44.0)", "mypy-boto3-appsync (>=1.43.0,<1.44.0)", "mypy-boto3-arc-region-switch (>=1.43.0,<1.44.0)", "mypy-boto3-arc-zonal-shift (>=1.43.0,<1.44.0)", "mypy-boto3-artifact (>=1.43.0,<1.44.0)", "mypy-boto3-athena (>=1.43.0,<1.44.0)", "mypy-boto3-auditmanager (>=1.43.0,<1.44.0)", "mypy-boto3-autoscaling (>=1.43.0,<1.44.0)", "mypy-boto3-autoscaling-plans (>=1.43.0,<1.44.0)", "mypy-boto3-b2bi (>=1.43.0,<1.44.0)", "mypy-boto3-backup (>=1.43.0,<1.44.0)", "mypy-boto3-backup-gateway (>=1.43.0,<1.44.0)", "mypy-boto3-backupsearch (>=1.43.0,<1.44.0)", "mypy-boto3-batch (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-dashboards (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-data-exports (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-pricing-calculator (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-recommended-actions (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agent (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agent-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agentcore (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agentcore-control (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-data-automation (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-data-automation-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-billing (>=1.43.0,<1.44.0)", "mypy-boto3-billingconductor (>=1.43.0,<1.44.0)", "mypy-boto3-braket (>=1.43.0,<1.44.0)", "mypy-boto3-budgets (>=1.43.0,<1.44.0)", "mypy-boto3-ce (>=1.43.0,<1.44.0)", "mypy-boto3-chatbot (>=1.43.0,<1.44.0)", "mypy-boto3-chime (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-identity (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-meetings (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-messaging (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-voice (>=1.43.0,<1.44.0)", "mypy-boto3-cleanrooms (>=1.43.0,<1.44.0)", "mypy-boto3-cleanroomsml (>=1.43.0,<1.44.0)", "mypy-boto3-cloud9 (>=1.43.0,<1.44.0)", "mypy-boto3-cloudcontrol (>=1.43.0,<1.44.0)", "mypy-boto3-clouddirectory (>=1.43.0,<1.44.0)", "mypy-boto3-cloudformation (>=1.43.0,<1.44.0)", "mypy-boto3-cloudfront (>=1.43.0,<1.44.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.43.0,<1.44.0)", "mypy-boto3-cloudhsm (>=1.43.0,<1.44.0)", "mypy-boto3-cloudhsmv2 (>=1.43.0,<1.44.0)", "mypy-boto3-cloudsearch (>=1.43.0,<1.44.0)", "mypy-boto3-cloudsearchdomain (>=1.43.0,<1.44.0)", "mypy-boto3-cloudtrail (>=1.43.0,<1.44.0)", "mypy-boto3-cloudtrail-data (>=1.43.0,<1.44.0)", "mypy-boto3-cloudwatch (>=1.43.0,<1.44.0)", "mypy-boto3-codeartifact (>=1.43.0,<1.44.0)", "mypy-boto3-codebuild (>=1.43.0,<1.44.0)", "mypy-boto3-codecatalyst (>=1.43.0,<1.44.0)", "mypy-boto3-codecommit (>=1.43.0,<1.44.0)", "mypy-boto3-codeconnections (>=1.43.0,<1.44.0)", "mypy-boto3-codedeploy (>=1.43.0,<1.44.0)", "mypy-boto3-codeguru-reviewer (>=1.43.0,<1.44.0)", "mypy-boto3-codeguru-security (>=1.43.0,<1.44.0)", "mypy-boto3-codeguruprofiler (>=1.43.0,<1.44.0)", "mypy-boto3-codepipeline (>=1.43.0,<1.44.0)", "mypy-boto3-codestar-connections (>=1.43.0,<1.44.0)", "mypy-boto3-codestar-notifications (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-identity (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-idp (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-sync (>=1.43.0,<1.44.0)", "mypy-boto3-comprehend (>=1.43.0,<1.44.0)", "mypy-boto3-comprehendmedical (>=1.43.0,<1.44.0)", "mypy-boto3-compute-optimizer (>=1.43.0,<1.44.0)", "mypy-boto3-compute-optimizer-automation (>=1.43.0,<1.44.0)", "mypy-boto3-config (>=1.43.0,<1.44.0)", "mypy-boto3-connect (>=1.43.0,<1.44.0)", "mypy-boto3-connect-contact-lens (>=1.43.0,<1.44.0)", "mypy-boto3-connectcampaigns (>=1.43.0,<1.44.0)", "mypy-boto3-connectcampaignsv2 (>=1.43.0,<1.44.0)", "mypy-boto3-connectcases (>=1.43.0,<1.44.0)", "mypy-boto3-connecthealth (>=1.43.0,<1.44.0)", "mypy-boto3-connectparticipant (>=1.43.0,<1.44.0)", "mypy-boto3-controlcatalog (>=1.43.0,<1.44.0)", "mypy-boto3-controltower (>=1.43.0,<1.44.0)", "mypy-boto3-cost-optimization-hub (>=1.43.0,<1.44.0)", "mypy-boto3-cur (>=1.43.0,<1.44.0)", "mypy-boto3-customer-profiles (>=1.43.0,<1.44.0)", "mypy-boto3-databrew (>=1.43.0,<1.44.0)", "mypy-boto3-dataexchange (>=1.43.0,<1.44.0)", "mypy-boto3-datapipeline (>=1.43.0,<1.44.0)", "mypy-boto3-datasync (>=1.43.0,<1.44.0)", "mypy-boto3-datazone (>=1.43.0,<1.44.0)", "mypy-boto3-dax (>=1.43.0,<1.44.0)", "mypy-boto3-deadline (>=1.43.0,<1.44.0)", "mypy-boto3-detective (>=1.43.0,<1.44.0)", "mypy-boto3-devicefarm (>=1.43.0,<1.44.0)", "mypy-boto3-devops-agent (>=1.43.0,<1.44.0)", "mypy-boto3-devops-guru (>=1.43.0,<1.44.0)", "mypy-boto3-directconnect (>=1.43.0,<1.44.0)", "mypy-boto3-discovery (>=1.43.0,<1.44.0)", "mypy-boto3-dlm (>=1.43.0,<1.44.0)", "mypy-boto3-dms (>=1.43.0,<1.44.0)", "mypy-boto3-docdb (>=1.43.0,<1.44.0)", "mypy-boto3-docdb-elastic (>=1.43.0,<1.44.0)", "mypy-boto3-drs (>=1.43.0,<1.44.0)", "mypy-boto3-ds (>=1.43.0,<1.44.0)", "mypy-boto3-ds-data (>=1.43.0,<1.44.0)", "mypy-boto3-dsql (>=1.43.0,<1.44.0)", "mypy-boto3-dynamodb (>=1.43.0,<1.44.0)", "mypy-boto3-dynamodbstreams (>=1.43.0,<1.44.0)", "mypy-boto3-ebs (>=1.43.0,<1.44.0)", "mypy-boto3-ec2 (>=1.43.0,<1.44.0)", "mypy-boto3-ec2-instance-connect (>=1.43.0,<1.44.0)", "mypy-boto3-ecr (>=1.43.0,<1.44.0)", "mypy-boto3-ecr-public (>=1.43.0,<1.44.0)", "mypy-boto3-ecs (>=1.43.0,<1.44.0)", "mypy-boto3-efs (>=1.43.0,<1.44.0)", "mypy-boto3-eks (>=1.43.0,<1.44.0)", "mypy-boto3-eks-auth (>=1.43.0,<1.44.0)", "mypy-boto3-elasticache (>=1.43.0,<1.44.0)", "mypy-boto3-elasticbeanstalk (>=1.43.0,<1.44.0)", "mypy-boto3-elb (>=1.43.0,<1.44.0)", "mypy-boto3-elbv2 (>=1.43.0,<1.44.0)", "mypy-boto3-elementalinference (>=1.43.0,<1.44.0)", "mypy-boto3-emr (>=1.43.0,<1.44.0)", "mypy-boto3-emr-containers (>=1.43.0,<1.44.0)", "mypy-boto3-emr-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-entityresolution (>=1.43.0,<1.44.0)", "mypy-boto3-es (>=1.43.0,<1.44.0)", "mypy-boto3-events (>=1.43.0,<1.44.0)", "mypy-boto3-evs (>=1.43.0,<1.44.0)", "mypy-boto3-finspace (>=1.43.0,<1.44.0)", "mypy-boto3-finspace-data (>=1.43.0,<1.44.0)", "mypy-boto3-firehose (>=1.43.0,<1.44.0)", "mypy-boto3-fis (>=1.43.0,<1.44.0)", "mypy-boto3-fms (>=1.43.0,<1.44.0)", "mypy-boto3-forecast (>=1.43.0,<1.44.0)", "mypy-boto3-forecastquery (>=1.43.0,<1.44.0)", "mypy-boto3-frauddetector (>=1.43.0,<1.44.0)", "mypy-boto3-freetier (>=1.43.0,<1.44.0)", "mypy-boto3-fsx (>=1.43.0,<1.44.0)", "mypy-boto3-gamelift (>=1.43.0,<1.44.0)", "mypy-boto3-gameliftstreams (>=1.43.0,<1.44.0)", "mypy-boto3-geo-maps (>=1.43.0,<1.44.0)", "mypy-boto3-geo-places (>=1.43.0,<1.44.0)", "mypy-boto3-geo-routes (>=1.43.0,<1.44.0)", "mypy-boto3-glacier (>=1.43.0,<1.44.0)", "mypy-boto3-globalaccelerator (>=1.43.0,<1.44.0)", "mypy-boto3-glue (>=1.43.0,<1.44.0)", "mypy-boto3-grafana (>=1.43.0,<1.44.0)", "mypy-boto3-greengrass (>=1.43.0,<1.44.0)", "mypy-boto3-greengrassv2 (>=1.43.0,<1.44.0)", "mypy-boto3-groundstation (>=1.43.0,<1.44.0)", "mypy-boto3-guardduty (>=1.43.0,<1.44.0)", "mypy-boto3-health (>=1.43.0,<1.44.0)", "mypy-boto3-healthlake (>=1.43.0,<1.44.0)", "mypy-boto3-iam (>=1.43.0,<1.44.0)", "mypy-boto3-identitystore (>=1.43.0,<1.44.0)", "mypy-boto3-imagebuilder (>=1.43.0,<1.44.0)", "mypy-boto3-importexport (>=1.43.0,<1.44.0)", "mypy-boto3-inspector (>=1.43.0,<1.44.0)", "mypy-boto3-inspector-scan (>=1.43.0,<1.44.0)", "mypy-boto3-inspector2 (>=1.43.0,<1.44.0)", "mypy-boto3-interconnect (>=1.43.0,<1.44.0)", "mypy-boto3-internetmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-invoicing (>=1.43.0,<1.44.0)", "mypy-boto3-iot (>=1.43.0,<1.44.0)", "mypy-boto3-iot-data (>=1.43.0,<1.44.0)", "mypy-boto3-iot-jobs-data (>=1.43.0,<1.44.0)", "mypy-boto3-iot-managed-integrations (>=1.43.0,<1.44.0)", "mypy-boto3-iotdeviceadvisor (>=1.43.0,<1.44.0)", "mypy-boto3-iotevents (>=1.43.0,<1.44.0)", "mypy-boto3-iotevents-data (>=1.43.0,<1.44.0)", "mypy-boto3-iotfleetwise (>=1.43.0,<1.44.0)", "mypy-boto3-iotsecuretunneling (>=1.43.0,<1.44.0)", "mypy-boto3-iotsitewise (>=1.43.0,<1.44.0)", "mypy-boto3-iotthingsgraph (>=1.43.0,<1.44.0)", "mypy-boto3-iottwinmaker (>=1.43.0,<1.44.0)", "mypy-boto3-iotwireless (>=1.43.0,<1.44.0)", "mypy-boto3-ivs (>=1.43.0,<1.44.0)", "mypy-boto3-ivs-realtime (>=1.43.0,<1.44.0)", "mypy-boto3-ivschat (>=1.43.0,<1.44.0)", "mypy-boto3-kafka (>=1.43.0,<1.44.0)", "mypy-boto3-kafkaconnect (>=1.43.0,<1.44.0)", "mypy-boto3-kendra (>=1.43.0,<1.44.0)", "mypy-boto3-kendra-ranking (>=1.43.0,<1.44.0)", "mypy-boto3-keyspaces (>=1.43.0,<1.44.0)", "mypy-boto3-keyspacesstreams (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-archived-media (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-media (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-signaling (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisanalytics (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisvideo (>=1.43.0,<1.44.0)", "mypy-boto3-kms (>=1.43.0,<1.44.0)", "mypy-boto3-lakeformation (>=1.43.0,<1.44.0)", "mypy-boto3-lambda (>=1.43.0,<1.44.0)", "mypy-boto3-launch-wizard (>=1.43.0,<1.44.0)", "mypy-boto3-lex-models (>=1.43.0,<1.44.0)", "mypy-boto3-lex-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-lexv2-models (>=1.43.0,<1.44.0)", "mypy-boto3-lexv2-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.43.0,<1.44.0)", "mypy-boto3-lightsail (>=1.43.0,<1.44.0)", "mypy-boto3-location (>=1.43.0,<1.44.0)", "mypy-boto3-logs (>=1.43.0,<1.44.0)", "mypy-boto3-lookoutequipment (>=1.43.0,<1.44.0)", "mypy-boto3-m2 (>=1.43.0,<1.44.0)", "mypy-boto3-machinelearning (>=1.43.0,<1.44.0)", "mypy-boto3-macie2 (>=1.43.0,<1.44.0)", "mypy-boto3-mailmanager (>=1.43.0,<1.44.0)", "mypy-boto3-managedblockchain (>=1.43.0,<1.44.0)", "mypy-boto3-managedblockchain-query (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-agreement (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-catalog (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-deployment (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-discovery (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-entitlement (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-reporting (>=1.43.0,<1.44.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.43.0,<1.44.0)", "mypy-boto3-mediaconnect (>=1.43.0,<1.44.0)", "mypy-boto3-mediaconvert (>=1.43.0,<1.44.0)", "mypy-boto3-medialive (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackage (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackage-vod (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackagev2 (>=1.43.0,<1.44.0)", "mypy-boto3-mediastore (>=1.43.0,<1.44.0)", "mypy-boto3-mediastore-data (>=1.43.0,<1.44.0)", "mypy-boto3-mediatailor (>=1.43.0,<1.44.0)", "mypy-boto3-medical-imaging (>=1.43.0,<1.44.0)", "mypy-boto3-memorydb (>=1.43.0,<1.44.0)", "mypy-boto3-meteringmarketplace (>=1.43.0,<1.44.0)", "mypy-boto3-mgh (>=1.43.0,<1.44.0)", "mypy-boto3-mgn (>=1.43.0,<1.44.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhub-config (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhuborchestrator (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhubstrategy (>=1.43.0,<1.44.0)", "mypy-boto3-mpa (>=1.43.0,<1.44.0)", "mypy-boto3-mq (>=1.43.0,<1.44.0)", "mypy-boto3-mturk (>=1.43.0,<1.44.0)", "mypy-boto3-mwaa (>=1.43.0,<1.44.0)", "mypy-boto3-mwaa-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-neptune (>=1.43.0,<1.44.0)", "mypy-boto3-neptune-graph (>=1.43.0,<1.44.0)", "mypy-boto3-neptunedata (>=1.43.0,<1.44.0)", "mypy-boto3-network-firewall (>=1.43.0,<1.44.0)", "mypy-boto3-networkflowmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-networkmanager (>=1.43.0,<1.44.0)", "mypy-boto3-networkmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-notifications (>=1.43.0,<1.44.0)", "mypy-boto3-notificationscontacts (>=1.43.0,<1.44.0)", "mypy-boto3-nova-act (>=1.43.0,<1.44.0)", "mypy-boto3-oam (>=1.43.0,<1.44.0)", "mypy-boto3-observabilityadmin (>=1.43.0,<1.44.0)", "mypy-boto3-odb (>=1.43.0,<1.44.0)", "mypy-boto3-omics (>=1.43.0,<1.44.0)", "mypy-boto3-opensearch (>=1.43.0,<1.44.0)", "mypy-boto3-opensearchserverless (>=1.43.0,<1.44.0)", "mypy-boto3-organizations (>=1.43.0,<1.44.0)", "mypy-boto3-osis (>=1.43.0,<1.44.0)", "mypy-boto3-outposts (>=1.43.0,<1.44.0)", "mypy-boto3-panorama (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-account (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-benefits (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-channel (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-selling (>=1.43.0,<1.44.0)", "mypy-boto3-payment-cryptography (>=1.43.0,<1.44.0)", "mypy-boto3-payment-cryptography-data (>=1.43.0,<1.44.0)", "mypy-boto3-pca-connector-ad (>=1.43.0,<1.44.0)", "mypy-boto3-pca-connector-scep (>=1.43.0,<1.44.0)", "mypy-boto3-pcs (>=1.43.0,<1.44.0)", "mypy-boto3-personalize (>=1.43.0,<1.44.0)", "mypy-boto3-personalize-events (>=1.43.0,<1.44.0)", "mypy-boto3-personalize-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-pi (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-email (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-sms-voice (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.43.0,<1.44.0)", "mypy-boto3-pipes (>=1.43.0,<1.44.0)", "mypy-boto3-polly (>=1.43.0,<1.44.0)", "mypy-boto3-pricing (>=1.43.0,<1.44.0)", "mypy-boto3-proton (>=1.43.0,<1.44.0)", "mypy-boto3-qapps (>=1.43.0,<1.44.0)", "mypy-boto3-qbusiness (>=1.43.0,<1.44.0)", "mypy-boto3-qconnect (>=1.43.0,<1.44.0)", "mypy-boto3-quicksight (>=1.43.0,<1.44.0)", "mypy-boto3-ram (>=1.43.0,<1.44.0)", "mypy-boto3-rbin (>=1.43.0,<1.44.0)", "mypy-boto3-rds (>=1.43.0,<1.44.0)", "mypy-boto3-rds-data (>=1.43.0,<1.44.0)", "mypy-boto3-redshift (>=1.43.0,<1.44.0)", "mypy-boto3-redshift-data (>=1.43.0,<1.44.0)", "mypy-boto3-redshift-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-rekognition (>=1.43.0,<1.44.0)", "mypy-boto3-repostspace (>=1.43.0,<1.44.0)", "mypy-boto3-resiliencehub (>=1.43.0,<1.44.0)", "mypy-boto3-resiliencehubv2 (>=1.43.0,<1.44.0)", "mypy-boto3-resource-explorer-2 (>=1.43.0,<1.44.0)", "mypy-boto3-resource-groups (>=1.43.0,<1.44.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.43.0,<1.44.0)", "mypy-boto3-rolesanywhere (>=1.43.0,<1.44.0)", "mypy-boto3-route53 (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-cluster (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-control-config (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-readiness (>=1.43.0,<1.44.0)", "mypy-boto3-route53domains (>=1.43.0,<1.44.0)", "mypy-boto3-route53globalresolver (>=1.43.0,<1.44.0)", "mypy-boto3-route53profiles (>=1.43.0,<1.44.0)", "mypy-boto3-route53resolver (>=1.43.0,<1.44.0)", "mypy-boto3-rtbfabric (>=1.43.0,<1.44.0)", "mypy-boto3-rum (>=1.43.0,<1.44.0)", "mypy-boto3-s3 (>=1.43.0,<1.44.0)", "mypy-boto3-s3control (>=1.43.0,<1.44.0)", "mypy-boto3-s3files (>=1.43.0,<1.44.0)", "mypy-boto3-s3outposts (>=1.43.0,<1.44.0)", "mypy-boto3-s3tables (>=1.43.0,<1.44.0)", "mypy-boto3-s3vectors (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-edge (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-geospatial (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-metrics (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemakerjobruntime (>=1.43.0,<1.44.0)", "mypy-boto3-savingsplans (>=1.43.0,<1.44.0)", "mypy-boto3-scheduler (>=1.43.0,<1.44.0)", "mypy-boto3-schemas (>=1.43.0,<1.44.0)", "mypy-boto3-sdb (>=1.43.0,<1.44.0)", "mypy-boto3-secretsmanager (>=1.43.0,<1.44.0)", "mypy-boto3-security-ir (>=1.43.0,<1.44.0)", "mypy-boto3-securityagent (>=1.43.0,<1.44.0)", "mypy-boto3-securityhub (>=1.43.0,<1.44.0)", "mypy-boto3-securitylake (>=1.43.0,<1.44.0)", "mypy-boto3-serverlessrepo (>=1.43.0,<1.44.0)", "mypy-boto3-service-quotas (>=1.43.0,<1.44.0)", "mypy-boto3-servicecatalog (>=1.43.0,<1.44.0)", "mypy-boto3-servicecatalog-appregistry (>=1.43.0,<1.44.0)", "mypy-boto3-servicediscovery (>=1.43.0,<1.44.0)", "mypy-boto3-ses (>=1.43.0,<1.44.0)", "mypy-boto3-sesv2 (>=1.43.0,<1.44.0)", "mypy-boto3-shield (>=1.43.0,<1.44.0)", "mypy-boto3-signer (>=1.43.0,<1.44.0)", "mypy-boto3-signer-data (>=1.43.0,<1.44.0)", "mypy-boto3-signin (>=1.43.0,<1.44.0)", "mypy-boto3-simpledbv2 (>=1.43.0,<1.44.0)", "mypy-boto3-simspaceweaver (>=1.43.0,<1.44.0)", "mypy-boto3-snow-device-management (>=1.43.0,<1.44.0)", "mypy-boto3-snowball (>=1.43.0,<1.44.0)", "mypy-boto3-sns (>=1.43.0,<1.44.0)", "mypy-boto3-socialmessaging (>=1.43.0,<1.44.0)", "mypy-boto3-sqs (>=1.43.0,<1.44.0)", "mypy-boto3-ssm (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-contacts (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-guiconnect (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-incidents (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-quicksetup (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-sap (>=1.43.0,<1.44.0)", "mypy-boto3-sso (>=1.43.0,<1.44.0)", "mypy-boto3-sso-admin (>=1.43.0,<1.44.0)", "mypy-boto3-sso-oidc (>=1.43.0,<1.44.0)", "mypy-boto3-stepfunctions (>=1.43.0,<1.44.0)", "mypy-boto3-storagegateway (>=1.43.0,<1.44.0)", "mypy-boto3-sts (>=1.43.0,<1.44.0)", "mypy-boto3-supplychain (>=1.43.0,<1.44.0)", "mypy-boto3-support (>=1.43.0,<1.44.0)", "mypy-boto3-support-app (>=1.43.0,<1.44.0)", "mypy-boto3-sustainability (>=1.43.0,<1.44.0)", "mypy-boto3-swf (>=1.43.0,<1.44.0)", "mypy-boto3-synthetics (>=1.43.0,<1.44.0)", "mypy-boto3-taxsettings (>=1.43.0,<1.44.0)", "mypy-boto3-textract (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-influxdb (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-query (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-write (>=1.43.0,<1.44.0)", "mypy-boto3-tnb (>=1.43.0,<1.44.0)", "mypy-boto3-transcribe (>=1.43.0,<1.44.0)", "mypy-boto3-transfer (>=1.43.0,<1.44.0)", "mypy-boto3-translate (>=1.43.0,<1.44.0)", "mypy-boto3-trustedadvisor (>=1.43.0,<1.44.0)", "mypy-boto3-uxc (>=1.43.0,<1.44.0)", "mypy-boto3-verifiedpermissions (>=1.43.0,<1.44.0)", "mypy-boto3-voice-id (>=1.43.0,<1.44.0)", "mypy-boto3-vpc-lattice (>=1.43.0,<1.44.0)", "mypy-boto3-waf (>=1.43.0,<1.44.0)", "mypy-boto3-waf-regional (>=1.43.0,<1.44.0)", "mypy-boto3-wafv2 (>=1.43.0,<1.44.0)", "mypy-boto3-wellarchitected (>=1.43.0,<1.44.0)", "mypy-boto3-wickr (>=1.43.0,<1.44.0)", "mypy-boto3-wisdom (>=1.43.0,<1.44.0)", "mypy-boto3-workdocs (>=1.43.0,<1.44.0)", "mypy-boto3-workmail (>=1.43.0,<1.44.0)", "mypy-boto3-workmailmessageflow (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-instances (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-thin-client (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-web (>=1.43.0,<1.44.0)", "mypy-boto3-xray (>=1.43.0,<1.44.0)"] +all = ["mypy-boto3-accessanalyzer (>=1.43.0,<1.44.0)", "mypy-boto3-account (>=1.43.0,<1.44.0)", "mypy-boto3-account-access (>=1.43.0,<1.44.0)", "mypy-boto3-acm (>=1.43.0,<1.44.0)", "mypy-boto3-acm-pca (>=1.43.0,<1.44.0)", "mypy-boto3-agent-registry (>=1.43.0,<1.44.0)", "mypy-boto3-agent-registry-control (>=1.43.0,<1.44.0)", "mypy-boto3-aiops (>=1.43.0,<1.44.0)", "mypy-boto3-amp (>=1.43.0,<1.44.0)", "mypy-boto3-amplify (>=1.43.0,<1.44.0)", "mypy-boto3-amplifybackend (>=1.43.0,<1.44.0)", "mypy-boto3-amplifyuibuilder (>=1.43.0,<1.44.0)", "mypy-boto3-apigateway (>=1.43.0,<1.44.0)", "mypy-boto3-apigatewaymanagementapi (>=1.43.0,<1.44.0)", "mypy-boto3-apigatewayv2 (>=1.43.0,<1.44.0)", "mypy-boto3-appconfig (>=1.43.0,<1.44.0)", "mypy-boto3-appconfigdata (>=1.43.0,<1.44.0)", "mypy-boto3-appfabric (>=1.43.0,<1.44.0)", "mypy-boto3-appflow (>=1.43.0,<1.44.0)", "mypy-boto3-appintegrations (>=1.43.0,<1.44.0)", "mypy-boto3-application-autoscaling (>=1.43.0,<1.44.0)", "mypy-boto3-application-insights (>=1.43.0,<1.44.0)", "mypy-boto3-application-signals (>=1.43.0,<1.44.0)", "mypy-boto3-applicationcostprofiler (>=1.43.0,<1.44.0)", "mypy-boto3-appmesh (>=1.43.0,<1.44.0)", "mypy-boto3-apprunner (>=1.43.0,<1.44.0)", "mypy-boto3-appstream (>=1.43.0,<1.44.0)", "mypy-boto3-appsync (>=1.43.0,<1.44.0)", "mypy-boto3-arc-region-switch (>=1.43.0,<1.44.0)", "mypy-boto3-arc-zonal-shift (>=1.43.0,<1.44.0)", "mypy-boto3-artifact (>=1.43.0,<1.44.0)", "mypy-boto3-athena (>=1.43.0,<1.44.0)", "mypy-boto3-auditmanager (>=1.43.0,<1.44.0)", "mypy-boto3-autoscaling (>=1.43.0,<1.44.0)", "mypy-boto3-autoscaling-plans (>=1.43.0,<1.44.0)", "mypy-boto3-b2bi (>=1.43.0,<1.44.0)", "mypy-boto3-backup (>=1.43.0,<1.44.0)", "mypy-boto3-backup-gateway (>=1.43.0,<1.44.0)", "mypy-boto3-backupsearch (>=1.43.0,<1.44.0)", "mypy-boto3-batch (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-dashboards (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-data-exports (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-pricing-calculator (>=1.43.0,<1.44.0)", "mypy-boto3-bcm-recommended-actions (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agent (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agent-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agentcore (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-agentcore-control (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-data-automation (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-data-automation-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-bedrock-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-billing (>=1.43.0,<1.44.0)", "mypy-boto3-billingconductor (>=1.43.0,<1.44.0)", "mypy-boto3-braket (>=1.43.0,<1.44.0)", "mypy-boto3-budgets (>=1.43.0,<1.44.0)", "mypy-boto3-ce (>=1.43.0,<1.44.0)", "mypy-boto3-chatbot (>=1.43.0,<1.44.0)", "mypy-boto3-chime (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-identity (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-media-pipelines (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-meetings (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-messaging (>=1.43.0,<1.44.0)", "mypy-boto3-chime-sdk-voice (>=1.43.0,<1.44.0)", "mypy-boto3-cleanrooms (>=1.43.0,<1.44.0)", "mypy-boto3-cleanroomsml (>=1.43.0,<1.44.0)", "mypy-boto3-cloud9 (>=1.43.0,<1.44.0)", "mypy-boto3-cloudcontrol (>=1.43.0,<1.44.0)", "mypy-boto3-clouddirectory (>=1.43.0,<1.44.0)", "mypy-boto3-cloudformation (>=1.43.0,<1.44.0)", "mypy-boto3-cloudfront (>=1.43.0,<1.44.0)", "mypy-boto3-cloudfront-keyvaluestore (>=1.43.0,<1.44.0)", "mypy-boto3-cloudhsm (>=1.43.0,<1.44.0)", "mypy-boto3-cloudhsmv2 (>=1.43.0,<1.44.0)", "mypy-boto3-cloudsearch (>=1.43.0,<1.44.0)", "mypy-boto3-cloudsearchdomain (>=1.43.0,<1.44.0)", "mypy-boto3-cloudtrail (>=1.43.0,<1.44.0)", "mypy-boto3-cloudtrail-data (>=1.43.0,<1.44.0)", "mypy-boto3-cloudwatch (>=1.43.0,<1.44.0)", "mypy-boto3-cloudwatchomni (>=1.43.0,<1.44.0)", "mypy-boto3-codeartifact (>=1.43.0,<1.44.0)", "mypy-boto3-codebuild (>=1.43.0,<1.44.0)", "mypy-boto3-codecatalyst (>=1.43.0,<1.44.0)", "mypy-boto3-codecommit (>=1.43.0,<1.44.0)", "mypy-boto3-codeconnections (>=1.43.0,<1.44.0)", "mypy-boto3-codedeploy (>=1.43.0,<1.44.0)", "mypy-boto3-codeguru-reviewer (>=1.43.0,<1.44.0)", "mypy-boto3-codeguru-security (>=1.43.0,<1.44.0)", "mypy-boto3-codeguruprofiler (>=1.43.0,<1.44.0)", "mypy-boto3-codepipeline (>=1.43.0,<1.44.0)", "mypy-boto3-codestar-connections (>=1.43.0,<1.44.0)", "mypy-boto3-codestar-notifications (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-identity (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-idp (>=1.43.0,<1.44.0)", "mypy-boto3-cognito-sync (>=1.43.0,<1.44.0)", "mypy-boto3-comprehend (>=1.43.0,<1.44.0)", "mypy-boto3-comprehendmedical (>=1.43.0,<1.44.0)", "mypy-boto3-compute-optimizer (>=1.43.0,<1.44.0)", "mypy-boto3-compute-optimizer-automation (>=1.43.0,<1.44.0)", "mypy-boto3-config (>=1.43.0,<1.44.0)", "mypy-boto3-connect (>=1.43.0,<1.44.0)", "mypy-boto3-connect-contact-lens (>=1.43.0,<1.44.0)", "mypy-boto3-connectcampaigns (>=1.43.0,<1.44.0)", "mypy-boto3-connectcampaignsv2 (>=1.43.0,<1.44.0)", "mypy-boto3-connectcases (>=1.43.0,<1.44.0)", "mypy-boto3-connecthealth (>=1.43.0,<1.44.0)", "mypy-boto3-connectparticipant (>=1.43.0,<1.44.0)", "mypy-boto3-controlcatalog (>=1.43.0,<1.44.0)", "mypy-boto3-controltower (>=1.43.0,<1.44.0)", "mypy-boto3-cost-optimization-hub (>=1.43.0,<1.44.0)", "mypy-boto3-cur (>=1.43.0,<1.44.0)", "mypy-boto3-customer-profiles (>=1.43.0,<1.44.0)", "mypy-boto3-databrew (>=1.43.0,<1.44.0)", "mypy-boto3-dataexchange (>=1.43.0,<1.44.0)", "mypy-boto3-datapipeline (>=1.43.0,<1.44.0)", "mypy-boto3-datasync (>=1.43.0,<1.44.0)", "mypy-boto3-datazone (>=1.43.0,<1.44.0)", "mypy-boto3-dax (>=1.43.0,<1.44.0)", "mypy-boto3-deadline (>=1.43.0,<1.44.0)", "mypy-boto3-detective (>=1.43.0,<1.44.0)", "mypy-boto3-devicefarm (>=1.43.0,<1.44.0)", "mypy-boto3-devops-agent (>=1.43.0,<1.44.0)", "mypy-boto3-devops-guru (>=1.43.0,<1.44.0)", "mypy-boto3-directconnect (>=1.43.0,<1.44.0)", "mypy-boto3-discovery (>=1.43.0,<1.44.0)", "mypy-boto3-dlm (>=1.43.0,<1.44.0)", "mypy-boto3-dms (>=1.43.0,<1.44.0)", "mypy-boto3-docdb (>=1.43.0,<1.44.0)", "mypy-boto3-docdb-elastic (>=1.43.0,<1.44.0)", "mypy-boto3-drs (>=1.43.0,<1.44.0)", "mypy-boto3-ds (>=1.43.0,<1.44.0)", "mypy-boto3-ds-data (>=1.43.0,<1.44.0)", "mypy-boto3-dsql (>=1.43.0,<1.44.0)", "mypy-boto3-dynamodb (>=1.43.0,<1.44.0)", "mypy-boto3-dynamodbstreams (>=1.43.0,<1.44.0)", "mypy-boto3-ebs (>=1.43.0,<1.44.0)", "mypy-boto3-ec2 (>=1.43.0,<1.44.0)", "mypy-boto3-ec2-instance-connect (>=1.43.0,<1.44.0)", "mypy-boto3-ecr (>=1.43.0,<1.44.0)", "mypy-boto3-ecr-public (>=1.43.0,<1.44.0)", "mypy-boto3-ecs (>=1.43.0,<1.44.0)", "mypy-boto3-efs (>=1.43.0,<1.44.0)", "mypy-boto3-eks (>=1.43.0,<1.44.0)", "mypy-boto3-eks-auth (>=1.43.0,<1.44.0)", "mypy-boto3-elasticache (>=1.43.0,<1.44.0)", "mypy-boto3-elasticbeanstalk (>=1.43.0,<1.44.0)", "mypy-boto3-elb (>=1.43.0,<1.44.0)", "mypy-boto3-elbv2 (>=1.43.0,<1.44.0)", "mypy-boto3-elementalinference (>=1.43.0,<1.44.0)", "mypy-boto3-emr (>=1.43.0,<1.44.0)", "mypy-boto3-emr-containers (>=1.43.0,<1.44.0)", "mypy-boto3-emr-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-endusermessaging (>=1.43.0,<1.44.0)", "mypy-boto3-entityresolution (>=1.43.0,<1.44.0)", "mypy-boto3-es (>=1.43.0,<1.44.0)", "mypy-boto3-eventbridgev2 (>=1.43.0,<1.44.0)", "mypy-boto3-events (>=1.43.0,<1.44.0)", "mypy-boto3-evs (>=1.43.0,<1.44.0)", "mypy-boto3-finspace (>=1.43.0,<1.44.0)", "mypy-boto3-finspace-data (>=1.43.0,<1.44.0)", "mypy-boto3-firehose (>=1.43.0,<1.44.0)", "mypy-boto3-fis (>=1.43.0,<1.44.0)", "mypy-boto3-fms (>=1.43.0,<1.44.0)", "mypy-boto3-forecast (>=1.43.0,<1.44.0)", "mypy-boto3-forecastquery (>=1.43.0,<1.44.0)", "mypy-boto3-frauddetector (>=1.43.0,<1.44.0)", "mypy-boto3-freetier (>=1.43.0,<1.44.0)", "mypy-boto3-fsx (>=1.43.0,<1.44.0)", "mypy-boto3-gamelift (>=1.43.0,<1.44.0)", "mypy-boto3-gameliftstreams (>=1.43.0,<1.44.0)", "mypy-boto3-geo-maps (>=1.43.0,<1.44.0)", "mypy-boto3-geo-places (>=1.43.0,<1.44.0)", "mypy-boto3-geo-routes (>=1.43.0,<1.44.0)", "mypy-boto3-glacier (>=1.43.0,<1.44.0)", "mypy-boto3-globalaccelerator (>=1.43.0,<1.44.0)", "mypy-boto3-glue (>=1.43.0,<1.44.0)", "mypy-boto3-grafana (>=1.43.0,<1.44.0)", "mypy-boto3-greengrass (>=1.43.0,<1.44.0)", "mypy-boto3-greengrassv2 (>=1.43.0,<1.44.0)", "mypy-boto3-groundstation (>=1.43.0,<1.44.0)", "mypy-boto3-guardduty (>=1.43.0,<1.44.0)", "mypy-boto3-health (>=1.43.0,<1.44.0)", "mypy-boto3-healthlake (>=1.43.0,<1.44.0)", "mypy-boto3-iam (>=1.43.0,<1.44.0)", "mypy-boto3-iam-toolbox (>=1.43.0,<1.44.0)", "mypy-boto3-identitystore (>=1.43.0,<1.44.0)", "mypy-boto3-imagebuilder (>=1.43.0,<1.44.0)", "mypy-boto3-importexport (>=1.43.0,<1.44.0)", "mypy-boto3-inspector (>=1.43.0,<1.44.0)", "mypy-boto3-inspector-scan (>=1.43.0,<1.44.0)", "mypy-boto3-inspector2 (>=1.43.0,<1.44.0)", "mypy-boto3-interconnect (>=1.43.0,<1.44.0)", "mypy-boto3-internetmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-invoicing (>=1.43.0,<1.44.0)", "mypy-boto3-iot (>=1.43.0,<1.44.0)", "mypy-boto3-iot-data (>=1.43.0,<1.44.0)", "mypy-boto3-iot-jobs-data (>=1.43.0,<1.44.0)", "mypy-boto3-iot-managed-integrations (>=1.43.0,<1.44.0)", "mypy-boto3-iotdeviceadvisor (>=1.43.0,<1.44.0)", "mypy-boto3-iotfleetwise (>=1.43.0,<1.44.0)", "mypy-boto3-iotsecuretunneling (>=1.43.0,<1.44.0)", "mypy-boto3-iotsitewise (>=1.43.0,<1.44.0)", "mypy-boto3-iotthingsgraph (>=1.43.0,<1.44.0)", "mypy-boto3-iottwinmaker (>=1.43.0,<1.44.0)", "mypy-boto3-iotwireless (>=1.43.0,<1.44.0)", "mypy-boto3-ivs (>=1.43.0,<1.44.0)", "mypy-boto3-ivs-realtime (>=1.43.0,<1.44.0)", "mypy-boto3-ivschat (>=1.43.0,<1.44.0)", "mypy-boto3-kafka (>=1.43.0,<1.44.0)", "mypy-boto3-kafkaconnect (>=1.43.0,<1.44.0)", "mypy-boto3-kendra (>=1.43.0,<1.44.0)", "mypy-boto3-kendra-ranking (>=1.43.0,<1.44.0)", "mypy-boto3-keyspaces (>=1.43.0,<1.44.0)", "mypy-boto3-keyspacesstreams (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-archived-media (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-media (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-signaling (>=1.43.0,<1.44.0)", "mypy-boto3-kinesis-video-webrtc-storage (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisanalytics (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisanalyticsv2 (>=1.43.0,<1.44.0)", "mypy-boto3-kinesisvideo (>=1.43.0,<1.44.0)", "mypy-boto3-kms (>=1.43.0,<1.44.0)", "mypy-boto3-lakeformation (>=1.43.0,<1.44.0)", "mypy-boto3-lambda (>=1.43.0,<1.44.0)", "mypy-boto3-lambda-core (>=1.43.0,<1.44.0)", "mypy-boto3-lambda-microvms (>=1.43.0,<1.44.0)", "mypy-boto3-lambda-web (>=1.43.0,<1.44.0)", "mypy-boto3-launch-wizard (>=1.43.0,<1.44.0)", "mypy-boto3-lex-models (>=1.43.0,<1.44.0)", "mypy-boto3-lex-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-lexv2-models (>=1.43.0,<1.44.0)", "mypy-boto3-lexv2-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager-linux-subscriptions (>=1.43.0,<1.44.0)", "mypy-boto3-license-manager-user-subscriptions (>=1.43.0,<1.44.0)", "mypy-boto3-lightsail (>=1.43.0,<1.44.0)", "mypy-boto3-location (>=1.43.0,<1.44.0)", "mypy-boto3-logs (>=1.43.0,<1.44.0)", "mypy-boto3-lookoutequipment (>=1.43.0,<1.44.0)", "mypy-boto3-m2 (>=1.43.0,<1.44.0)", "mypy-boto3-machinelearning (>=1.43.0,<1.44.0)", "mypy-boto3-macie2 (>=1.43.0,<1.44.0)", "mypy-boto3-mailmanager (>=1.43.0,<1.44.0)", "mypy-boto3-managedblockchain (>=1.43.0,<1.44.0)", "mypy-boto3-managedblockchain-query (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-agreement (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-catalog (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-deployment (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-discovery (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-entitlement (>=1.43.0,<1.44.0)", "mypy-boto3-marketplace-reporting (>=1.43.0,<1.44.0)", "mypy-boto3-marketplacecommerceanalytics (>=1.43.0,<1.44.0)", "mypy-boto3-mediaconnect (>=1.43.0,<1.44.0)", "mypy-boto3-mediaconvert (>=1.43.0,<1.44.0)", "mypy-boto3-medialive (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackage (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackage-vod (>=1.43.0,<1.44.0)", "mypy-boto3-mediapackagev2 (>=1.43.0,<1.44.0)", "mypy-boto3-mediastore (>=1.43.0,<1.44.0)", "mypy-boto3-mediastore-data (>=1.43.0,<1.44.0)", "mypy-boto3-mediatailor (>=1.43.0,<1.44.0)", "mypy-boto3-medical-imaging (>=1.43.0,<1.44.0)", "mypy-boto3-memorydb (>=1.43.0,<1.44.0)", "mypy-boto3-meteringmarketplace (>=1.43.0,<1.44.0)", "mypy-boto3-mgh (>=1.43.0,<1.44.0)", "mypy-boto3-mgn (>=1.43.0,<1.44.0)", "mypy-boto3-migration-hub-refactor-spaces (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhub-config (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhuborchestrator (>=1.43.0,<1.44.0)", "mypy-boto3-migrationhubstrategy (>=1.43.0,<1.44.0)", "mypy-boto3-mpa (>=1.43.0,<1.44.0)", "mypy-boto3-mq (>=1.43.0,<1.44.0)", "mypy-boto3-mturk (>=1.43.0,<1.44.0)", "mypy-boto3-mwaa (>=1.43.0,<1.44.0)", "mypy-boto3-mwaa-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-neptune (>=1.43.0,<1.44.0)", "mypy-boto3-neptune-graph (>=1.43.0,<1.44.0)", "mypy-boto3-neptunedata (>=1.43.0,<1.44.0)", "mypy-boto3-network-firewall (>=1.43.0,<1.44.0)", "mypy-boto3-network-security-manager (>=1.43.0,<1.44.0)", "mypy-boto3-networkflowmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-networkmanager (>=1.43.0,<1.44.0)", "mypy-boto3-networkmonitor (>=1.43.0,<1.44.0)", "mypy-boto3-notifications (>=1.43.0,<1.44.0)", "mypy-boto3-notificationscontacts (>=1.43.0,<1.44.0)", "mypy-boto3-nova-act (>=1.43.0,<1.44.0)", "mypy-boto3-oam (>=1.43.0,<1.44.0)", "mypy-boto3-observabilityadmin (>=1.43.0,<1.44.0)", "mypy-boto3-odb (>=1.43.0,<1.44.0)", "mypy-boto3-omics (>=1.43.0,<1.44.0)", "mypy-boto3-opensearch (>=1.43.0,<1.44.0)", "mypy-boto3-opensearchserverless (>=1.43.0,<1.44.0)", "mypy-boto3-organizations (>=1.43.0,<1.44.0)", "mypy-boto3-osis (>=1.43.0,<1.44.0)", "mypy-boto3-outposts (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-account (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-benefits (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-channel (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-revenue-measurement (>=1.43.0,<1.44.0)", "mypy-boto3-partnercentral-selling (>=1.43.0,<1.44.0)", "mypy-boto3-payment-cryptography (>=1.43.0,<1.44.0)", "mypy-boto3-payment-cryptography-data (>=1.43.0,<1.44.0)", "mypy-boto3-pca-connector-ad (>=1.43.0,<1.44.0)", "mypy-boto3-pca-connector-scep (>=1.43.0,<1.44.0)", "mypy-boto3-pcs (>=1.43.0,<1.44.0)", "mypy-boto3-personalize (>=1.43.0,<1.44.0)", "mypy-boto3-personalize-events (>=1.43.0,<1.44.0)", "mypy-boto3-personalize-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-pi (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-email (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-sms-voice (>=1.43.0,<1.44.0)", "mypy-boto3-pinpoint-sms-voice-v2 (>=1.43.0,<1.44.0)", "mypy-boto3-pipes (>=1.43.0,<1.44.0)", "mypy-boto3-polly (>=1.43.0,<1.44.0)", "mypy-boto3-pricing (>=1.43.0,<1.44.0)", "mypy-boto3-pricing-plan-manager (>=1.43.0,<1.44.0)", "mypy-boto3-proton (>=1.43.0,<1.44.0)", "mypy-boto3-qapps (>=1.43.0,<1.44.0)", "mypy-boto3-qbusiness (>=1.43.0,<1.44.0)", "mypy-boto3-qconnect (>=1.43.0,<1.44.0)", "mypy-boto3-quicksight (>=1.43.0,<1.44.0)", "mypy-boto3-ram (>=1.43.0,<1.44.0)", "mypy-boto3-rbin (>=1.43.0,<1.44.0)", "mypy-boto3-rds (>=1.43.0,<1.44.0)", "mypy-boto3-rds-data (>=1.43.0,<1.44.0)", "mypy-boto3-redshift (>=1.43.0,<1.44.0)", "mypy-boto3-redshift-data (>=1.43.0,<1.44.0)", "mypy-boto3-redshift-serverless (>=1.43.0,<1.44.0)", "mypy-boto3-rekognition (>=1.43.0,<1.44.0)", "mypy-boto3-repostspace (>=1.43.0,<1.44.0)", "mypy-boto3-resiliencehub (>=1.43.0,<1.44.0)", "mypy-boto3-resiliencehubv2 (>=1.43.0,<1.44.0)", "mypy-boto3-resource-explorer-2 (>=1.43.0,<1.44.0)", "mypy-boto3-resource-groups (>=1.43.0,<1.44.0)", "mypy-boto3-resourcegroupstaggingapi (>=1.43.0,<1.44.0)", "mypy-boto3-rolesanywhere (>=1.43.0,<1.44.0)", "mypy-boto3-route53 (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-cluster (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-control-config (>=1.43.0,<1.44.0)", "mypy-boto3-route53-recovery-readiness (>=1.43.0,<1.44.0)", "mypy-boto3-route53domains (>=1.43.0,<1.44.0)", "mypy-boto3-route53globalresolver (>=1.43.0,<1.44.0)", "mypy-boto3-route53profiles (>=1.43.0,<1.44.0)", "mypy-boto3-route53resolver (>=1.43.0,<1.44.0)", "mypy-boto3-rtbfabric (>=1.43.0,<1.44.0)", "mypy-boto3-rum (>=1.43.0,<1.44.0)", "mypy-boto3-s3 (>=1.43.0,<1.44.0)", "mypy-boto3-s3control (>=1.43.0,<1.44.0)", "mypy-boto3-s3files (>=1.43.0,<1.44.0)", "mypy-boto3-s3outposts (>=1.43.0,<1.44.0)", "mypy-boto3-s3tables (>=1.43.0,<1.44.0)", "mypy-boto3-s3vectors (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-a2i-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-edge (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-featurestore-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-geospatial (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-metrics (>=1.43.0,<1.44.0)", "mypy-boto3-sagemaker-runtime (>=1.43.0,<1.44.0)", "mypy-boto3-sagemakerjobruntime (>=1.43.0,<1.44.0)", "mypy-boto3-savingsplans (>=1.43.0,<1.44.0)", "mypy-boto3-scheduler (>=1.43.0,<1.44.0)", "mypy-boto3-schemas (>=1.43.0,<1.44.0)", "mypy-boto3-sdb (>=1.43.0,<1.44.0)", "mypy-boto3-secretsmanager (>=1.43.0,<1.44.0)", "mypy-boto3-security-ir (>=1.43.0,<1.44.0)", "mypy-boto3-securityagent (>=1.43.0,<1.44.0)", "mypy-boto3-securityhub (>=1.43.0,<1.44.0)", "mypy-boto3-securitylake (>=1.43.0,<1.44.0)", "mypy-boto3-serverlessrepo (>=1.43.0,<1.44.0)", "mypy-boto3-service-quotas (>=1.43.0,<1.44.0)", "mypy-boto3-servicecatalog (>=1.43.0,<1.44.0)", "mypy-boto3-servicecatalog-appregistry (>=1.43.0,<1.44.0)", "mypy-boto3-servicediscovery (>=1.43.0,<1.44.0)", "mypy-boto3-ses (>=1.43.0,<1.44.0)", "mypy-boto3-sesv2 (>=1.43.0,<1.44.0)", "mypy-boto3-shield (>=1.43.0,<1.44.0)", "mypy-boto3-signer (>=1.43.0,<1.44.0)", "mypy-boto3-signer-data (>=1.43.0,<1.44.0)", "mypy-boto3-signin (>=1.43.0,<1.44.0)", "mypy-boto3-simpledbv2 (>=1.43.0,<1.44.0)", "mypy-boto3-snow-device-management (>=1.43.0,<1.44.0)", "mypy-boto3-snowball (>=1.43.0,<1.44.0)", "mypy-boto3-sns (>=1.43.0,<1.44.0)", "mypy-boto3-socialmessaging (>=1.43.0,<1.44.0)", "mypy-boto3-sqs (>=1.43.0,<1.44.0)", "mypy-boto3-ssm (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-contacts (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-guiconnect (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-incidents (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-quicksetup (>=1.43.0,<1.44.0)", "mypy-boto3-ssm-sap (>=1.43.0,<1.44.0)", "mypy-boto3-sso (>=1.43.0,<1.44.0)", "mypy-boto3-sso-admin (>=1.43.0,<1.44.0)", "mypy-boto3-sso-oidc (>=1.43.0,<1.44.0)", "mypy-boto3-stepfunctions (>=1.43.0,<1.44.0)", "mypy-boto3-storagegateway (>=1.43.0,<1.44.0)", "mypy-boto3-sts (>=1.43.0,<1.44.0)", "mypy-boto3-supplychain (>=1.43.0,<1.44.0)", "mypy-boto3-support (>=1.43.0,<1.44.0)", "mypy-boto3-support-app (>=1.43.0,<1.44.0)", "mypy-boto3-supportauthz (>=1.43.0,<1.44.0)", "mypy-boto3-sustainability (>=1.43.0,<1.44.0)", "mypy-boto3-swf (>=1.43.0,<1.44.0)", "mypy-boto3-synthetics (>=1.43.0,<1.44.0)", "mypy-boto3-taxsettings (>=1.43.0,<1.44.0)", "mypy-boto3-textract (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-influxdb (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-query (>=1.43.0,<1.44.0)", "mypy-boto3-timestream-write (>=1.43.0,<1.44.0)", "mypy-boto3-tnb (>=1.43.0,<1.44.0)", "mypy-boto3-transcribe (>=1.43.0,<1.44.0)", "mypy-boto3-transfer (>=1.43.0,<1.44.0)", "mypy-boto3-translate (>=1.43.0,<1.44.0)", "mypy-boto3-trustedadvisor (>=1.43.0,<1.44.0)", "mypy-boto3-uxc (>=1.43.0,<1.44.0)", "mypy-boto3-verifiedpermissions (>=1.43.0,<1.44.0)", "mypy-boto3-voice-id (>=1.43.0,<1.44.0)", "mypy-boto3-vpc-lattice (>=1.43.0,<1.44.0)", "mypy-boto3-waf (>=1.43.0,<1.44.0)", "mypy-boto3-waf-regional (>=1.43.0,<1.44.0)", "mypy-boto3-wafv2 (>=1.43.0,<1.44.0)", "mypy-boto3-wellarchitected (>=1.43.0,<1.44.0)", "mypy-boto3-wickr (>=1.43.0,<1.44.0)", "mypy-boto3-wisdom (>=1.43.0,<1.44.0)", "mypy-boto3-workdocs (>=1.43.0,<1.44.0)", "mypy-boto3-workmail (>=1.43.0,<1.44.0)", "mypy-boto3-workmailmessageflow (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-instances (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-thin-client (>=1.43.0,<1.44.0)", "mypy-boto3-workspaces-web (>=1.43.0,<1.44.0)", "mypy-boto3-xray (>=1.43.0,<1.44.0)"] amp = ["mypy-boto3-amp (>=1.43.0,<1.44.0)"] amplify = ["mypy-boto3-amplify (>=1.43.0,<1.44.0)"] amplifybackend = ["mypy-boto3-amplifybackend (>=1.43.0,<1.44.0)"] @@ -208,7 +235,7 @@ bedrock-data-automation-runtime = ["mypy-boto3-bedrock-data-automation-runtime ( bedrock-runtime = ["mypy-boto3-bedrock-runtime (>=1.43.0,<1.44.0)"] billing = ["mypy-boto3-billing (>=1.43.0,<1.44.0)"] billingconductor = ["mypy-boto3-billingconductor (>=1.43.0,<1.44.0)"] -boto3 = ["boto3 (==1.43.34)"] +boto3 = ["boto3 (==1.43.108)"] braket = ["mypy-boto3-braket (>=1.43.0,<1.44.0)"] budgets = ["mypy-boto3-budgets (>=1.43.0,<1.44.0)"] ce = ["mypy-boto3-ce (>=1.43.0,<1.44.0)"] @@ -234,6 +261,7 @@ cloudsearchdomain = ["mypy-boto3-cloudsearchdomain (>=1.43.0,<1.44.0)"] cloudtrail = ["mypy-boto3-cloudtrail (>=1.43.0,<1.44.0)"] cloudtrail-data = ["mypy-boto3-cloudtrail-data (>=1.43.0,<1.44.0)"] cloudwatch = ["mypy-boto3-cloudwatch (>=1.43.0,<1.44.0)"] +cloudwatchomni = ["mypy-boto3-cloudwatchomni (>=1.43.0,<1.44.0)"] codeartifact = ["mypy-boto3-codeartifact (>=1.43.0,<1.44.0)"] codebuild = ["mypy-boto3-codebuild (>=1.43.0,<1.44.0)"] codecatalyst = ["mypy-boto3-codecatalyst (>=1.43.0,<1.44.0)"] @@ -306,9 +334,11 @@ elementalinference = ["mypy-boto3-elementalinference (>=1.43.0,<1.44.0)"] emr = ["mypy-boto3-emr (>=1.43.0,<1.44.0)"] emr-containers = ["mypy-boto3-emr-containers (>=1.43.0,<1.44.0)"] emr-serverless = ["mypy-boto3-emr-serverless (>=1.43.0,<1.44.0)"] +endusermessaging = ["mypy-boto3-endusermessaging (>=1.43.0,<1.44.0)"] entityresolution = ["mypy-boto3-entityresolution (>=1.43.0,<1.44.0)"] es = ["mypy-boto3-es (>=1.43.0,<1.44.0)"] essential = ["mypy-boto3-cloudformation (>=1.43.0,<1.44.0)", "mypy-boto3-dynamodb (>=1.43.0,<1.44.0)", "mypy-boto3-ec2 (>=1.43.0,<1.44.0)", "mypy-boto3-lambda (>=1.43.0,<1.44.0)", "mypy-boto3-rds (>=1.43.0,<1.44.0)", "mypy-boto3-s3 (>=1.43.0,<1.44.0)", "mypy-boto3-sqs (>=1.43.0,<1.44.0)"] +eventbridgev2 = ["mypy-boto3-eventbridgev2 (>=1.43.0,<1.44.0)"] events = ["mypy-boto3-events (>=1.43.0,<1.44.0)"] evs = ["mypy-boto3-evs (>=1.43.0,<1.44.0)"] finspace = ["mypy-boto3-finspace (>=1.43.0,<1.44.0)"] @@ -338,6 +368,7 @@ guardduty = ["mypy-boto3-guardduty (>=1.43.0,<1.44.0)"] health = ["mypy-boto3-health (>=1.43.0,<1.44.0)"] healthlake = ["mypy-boto3-healthlake (>=1.43.0,<1.44.0)"] iam = ["mypy-boto3-iam (>=1.43.0,<1.44.0)"] +iam-toolbox = ["mypy-boto3-iam-toolbox (>=1.43.0,<1.44.0)"] identitystore = ["mypy-boto3-identitystore (>=1.43.0,<1.44.0)"] imagebuilder = ["mypy-boto3-imagebuilder (>=1.43.0,<1.44.0)"] importexport = ["mypy-boto3-importexport (>=1.43.0,<1.44.0)"] @@ -352,8 +383,6 @@ iot-data = ["mypy-boto3-iot-data (>=1.43.0,<1.44.0)"] iot-jobs-data = ["mypy-boto3-iot-jobs-data (>=1.43.0,<1.44.0)"] iot-managed-integrations = ["mypy-boto3-iot-managed-integrations (>=1.43.0,<1.44.0)"] iotdeviceadvisor = ["mypy-boto3-iotdeviceadvisor (>=1.43.0,<1.44.0)"] -iotevents = ["mypy-boto3-iotevents (>=1.43.0,<1.44.0)"] -iotevents-data = ["mypy-boto3-iotevents-data (>=1.43.0,<1.44.0)"] iotfleetwise = ["mypy-boto3-iotfleetwise (>=1.43.0,<1.44.0)"] iotsecuretunneling = ["mypy-boto3-iotsecuretunneling (>=1.43.0,<1.44.0)"] iotsitewise = ["mypy-boto3-iotsitewise (>=1.43.0,<1.44.0)"] @@ -380,6 +409,9 @@ kinesisvideo = ["mypy-boto3-kinesisvideo (>=1.43.0,<1.44.0)"] kms = ["mypy-boto3-kms (>=1.43.0,<1.44.0)"] lakeformation = ["mypy-boto3-lakeformation (>=1.43.0,<1.44.0)"] lambda = ["mypy-boto3-lambda (>=1.43.0,<1.44.0)"] +lambda-core = ["mypy-boto3-lambda-core (>=1.43.0,<1.44.0)"] +lambda-microvms = ["mypy-boto3-lambda-microvms (>=1.43.0,<1.44.0)"] +lambda-web = ["mypy-boto3-lambda-web (>=1.43.0,<1.44.0)"] launch-wizard = ["mypy-boto3-launch-wizard (>=1.43.0,<1.44.0)"] lex-models = ["mypy-boto3-lex-models (>=1.43.0,<1.44.0)"] lex-runtime = ["mypy-boto3-lex-runtime (>=1.43.0,<1.44.0)"] @@ -432,6 +464,7 @@ neptune = ["mypy-boto3-neptune (>=1.43.0,<1.44.0)"] neptune-graph = ["mypy-boto3-neptune-graph (>=1.43.0,<1.44.0)"] neptunedata = ["mypy-boto3-neptunedata (>=1.43.0,<1.44.0)"] network-firewall = ["mypy-boto3-network-firewall (>=1.43.0,<1.44.0)"] +network-security-manager = ["mypy-boto3-network-security-manager (>=1.43.0,<1.44.0)"] networkflowmonitor = ["mypy-boto3-networkflowmonitor (>=1.43.0,<1.44.0)"] networkmanager = ["mypy-boto3-networkmanager (>=1.43.0,<1.44.0)"] networkmonitor = ["mypy-boto3-networkmonitor (>=1.43.0,<1.44.0)"] @@ -447,10 +480,10 @@ opensearchserverless = ["mypy-boto3-opensearchserverless (>=1.43.0,<1.44.0)"] organizations = ["mypy-boto3-organizations (>=1.43.0,<1.44.0)"] osis = ["mypy-boto3-osis (>=1.43.0,<1.44.0)"] outposts = ["mypy-boto3-outposts (>=1.43.0,<1.44.0)"] -panorama = ["mypy-boto3-panorama (>=1.43.0,<1.44.0)"] partnercentral-account = ["mypy-boto3-partnercentral-account (>=1.43.0,<1.44.0)"] partnercentral-benefits = ["mypy-boto3-partnercentral-benefits (>=1.43.0,<1.44.0)"] partnercentral-channel = ["mypy-boto3-partnercentral-channel (>=1.43.0,<1.44.0)"] +partnercentral-revenue-measurement = ["mypy-boto3-partnercentral-revenue-measurement (>=1.43.0,<1.44.0)"] partnercentral-selling = ["mypy-boto3-partnercentral-selling (>=1.43.0,<1.44.0)"] payment-cryptography = ["mypy-boto3-payment-cryptography (>=1.43.0,<1.44.0)"] payment-cryptography-data = ["mypy-boto3-payment-cryptography-data (>=1.43.0,<1.44.0)"] @@ -468,6 +501,7 @@ pinpoint-sms-voice-v2 = ["mypy-boto3-pinpoint-sms-voice-v2 (>=1.43.0,<1.44.0)"] pipes = ["mypy-boto3-pipes (>=1.43.0,<1.44.0)"] polly = ["mypy-boto3-polly (>=1.43.0,<1.44.0)"] pricing = ["mypy-boto3-pricing (>=1.43.0,<1.44.0)"] +pricing-plan-manager = ["mypy-boto3-pricing-plan-manager (>=1.43.0,<1.44.0)"] proton = ["mypy-boto3-proton (>=1.43.0,<1.44.0)"] qapps = ["mypy-boto3-qapps (>=1.43.0,<1.44.0)"] qbusiness = ["mypy-boto3-qbusiness (>=1.43.0,<1.44.0)"] @@ -533,7 +567,6 @@ signer = ["mypy-boto3-signer (>=1.43.0,<1.44.0)"] signer-data = ["mypy-boto3-signer-data (>=1.43.0,<1.44.0)"] signin = ["mypy-boto3-signin (>=1.43.0,<1.44.0)"] simpledbv2 = ["mypy-boto3-simpledbv2 (>=1.43.0,<1.44.0)"] -simspaceweaver = ["mypy-boto3-simspaceweaver (>=1.43.0,<1.44.0)"] snow-device-management = ["mypy-boto3-snow-device-management (>=1.43.0,<1.44.0)"] snowball = ["mypy-boto3-snowball (>=1.43.0,<1.44.0)"] sns = ["mypy-boto3-sns (>=1.43.0,<1.44.0)"] @@ -554,6 +587,7 @@ sts = ["mypy-boto3-sts (>=1.43.0,<1.44.0)"] supplychain = ["mypy-boto3-supplychain (>=1.43.0,<1.44.0)"] support = ["mypy-boto3-support (>=1.43.0,<1.44.0)"] support-app = ["mypy-boto3-support-app (>=1.43.0,<1.44.0)"] +supportauthz = ["mypy-boto3-supportauthz (>=1.43.0,<1.44.0)"] sustainability = ["mypy-boto3-sustainability (>=1.43.0,<1.44.0)"] swf = ["mypy-boto3-swf (>=1.43.0,<1.44.0)"] synthetics = ["mypy-boto3-synthetics (>=1.43.0,<1.44.0)"] @@ -588,14 +622,14 @@ xray = ["mypy-boto3-xray (>=1.43.0,<1.44.0)"] [[package]] name = "botocore" -version = "1.43.36" +version = "1.43.108" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "botocore-1.43.36-py3-none-any.whl", hash = "sha256:3c65fdc39ed01d8dfde1e961b34038aed03c459f8ddf80717a12ac006475e49d"}, - {file = "botocore-1.43.36.tar.gz", hash = "sha256:4cae47d1b2d426316b85a0087d9e69e048f13bc003b5177d74639fe9dfd28205"}, + {file = "botocore-1.43.108-py3-none-any.whl", hash = "sha256:ab9d16c6b4350aaa54ed28202dfa2998b2d735fdbf3247eb60af469d8d48a5b8"}, + {file = "botocore-1.43.108.tar.gz", hash = "sha256:ee4f75cf3bdbb0da7912e089950e8112f692016539d939312c771499958e6cfd"}, ] [package.dependencies] @@ -604,130 +638,143 @@ python-dateutil = ">=2.1,<3.0.0" urllib3 = ">=1.25.4,<2.2.0 || >2.2.0,<3" [package.extras] -crt = ["awscrt (==0.32.2)"] +crt = ["awscrt (==0.36.0)"] [[package]] name = "botocore-stubs" -version = "1.42.41" +version = "1.43.67" description = "Type annotations and code completion for botocore" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "botocore_stubs-1.42.41-py3-none-any.whl", hash = "sha256:9423110fb0e391834bd2ed44ae5f879d8cb370a444703d966d30842ce2bcb5f0"}, - {file = "botocore_stubs-1.42.41.tar.gz", hash = "sha256:dbeac2f744df6b814ce83ec3f3777b299a015cbea57a2efc41c33b8c38265825"}, + {file = "botocore_stubs-1.43.67-py3-none-any.whl", hash = "sha256:c51262bac3341c1cda71f05fa01141fffd3990d7a92c7960e3b755c1bc830373"}, + {file = "botocore_stubs-1.43.67.tar.gz", hash = "sha256:853e74014a1f557055c4ffae5fb38d7c65c7c0520e1aab366cac41d5428f419d"}, ] -[package.dependencies] -types-awscrt = "*" - [package.extras] botocore = ["botocore"] [[package]] name = "certifi" -version = "2026.4.22" +version = "2026.7.22" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.7" groups = ["main", "dev", "docs"] files = [ - {file = "certifi-2026.4.22-py3-none-any.whl", hash = "sha256:3cb2210c8f88ba2318d29b0388d1023c8492ff72ecdde4ebdaddbb13a31b1c4a"}, - {file = "certifi-2026.4.22.tar.gz", hash = "sha256:8d455352a37b71bf76a79caa83a3d6c25afee4a385d632127b6afb3963f1c580"}, + {file = "certifi-2026.7.22-py3-none-any.whl", hash = "sha256:62f22742b58a1a33014a2b6b706588a8d7e2a88ae7bd1a6ebe8c992928483775"}, + {file = "certifi-2026.7.22.tar.gz", hash = "sha256:741e2c3b351ddf169a738da9f2c048608ff7f2c5cc02f1ebc6b118bb090d5d55"}, ] [[package]] name = "cffi" -version = "2.0.0" +version = "2.1.1" description = "Foreign Function Interface for Python calling C code." optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44"}, - {file = "cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4"}, - {file = "cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5"}, - {file = "cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb"}, - {file = "cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a"}, - {file = "cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe"}, - {file = "cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664"}, - {file = "cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414"}, - {file = "cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743"}, - {file = "cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5"}, - {file = "cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5"}, - {file = "cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d"}, - {file = "cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037"}, - {file = "cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94"}, - {file = "cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187"}, - {file = "cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18"}, - {file = "cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5"}, - {file = "cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb"}, - {file = "cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3"}, - {file = "cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c"}, - {file = "cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b"}, - {file = "cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27"}, - {file = "cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75"}, - {file = "cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5"}, - {file = "cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef"}, - {file = "cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205"}, - {file = "cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1"}, - {file = "cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f"}, - {file = "cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25"}, - {file = "cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9"}, - {file = "cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc"}, - {file = "cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512"}, - {file = "cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4"}, - {file = "cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e"}, - {file = "cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6"}, - {file = "cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_10_13_x86_64.whl", hash = "sha256:fe562eb1a64e67dd297ccc4f5addea2501664954f2692b69a76449ec7913ecbf"}, - {file = "cffi-2.0.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:de8dad4425a6ca6e4e5e297b27b5c824ecc7581910bf9aee86cb6835e6812aa7"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:4647afc2f90d1ddd33441e5b0e85b16b12ddec4fca55f0d9671fef036ecca27c"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3f4d46d8b35698056ec29bca21546e1551a205058ae1a181d871e278b0b28165"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e6e73b9e02893c764e7e8d5bb5ce277f1a009cd5243f8228f75f842bf937c534"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:cb527a79772e5ef98fb1d700678fe031e353e765d1ca2d409c92263c6d43e09f"}, - {file = "cffi-2.0.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:61d028e90346df14fedc3d1e5441df818d095f3b87d286825dfcbd6459b7ef63"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0f6084a0ea23d05d20c3edcda20c3d006f9b6f3fefeac38f59262e10cef47ee2"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:1cd13c99ce269b3ed80b417dcd591415d3372bcac067009b6e0f59c7d4015e65"}, - {file = "cffi-2.0.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:89472c9762729b5ae1ad974b777416bfda4ac5642423fa93bd57a09204712322"}, - {file = "cffi-2.0.0-cp39-cp39-win32.whl", hash = "sha256:2081580ebb843f759b9f617314a24ed5738c51d2aee65d31e02f6f7a2b97707a"}, - {file = "cffi-2.0.0-cp39-cp39-win_amd64.whl", hash = "sha256:b882b3df248017dba09d6b16defe9b5c407fe32fc7c65a9c69798e6175601be9"}, - {file = "cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529"}, + {file = "cffi-2.1.1-cp310-cp310-macosx_10_15_x86_64.whl", hash = "sha256:baed1e86cc735622097354b9d1281406caf42ff42a886d29faa8e8d1630333be"}, + {file = "cffi-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ca82be1a1d406ecfe1d25dc16cb33488e5a16bf4438c9fb590484ea29d92478b"}, + {file = "cffi-2.1.1-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:42e2f76b9455f5a9a844f770bf3e200ed3da0e15f5df3db9c31fe80b04b3d004"}, + {file = "cffi-2.1.1-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:5a59cc1c4442bc3d5c703bf720b51138d0bfc173618807c9ee2490a7541dd3d9"}, + {file = "cffi-2.1.1-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:9f8d177621de5cb38ee3e731eda45d421db093ec0739f46a5594babda7987a98"}, + {file = "cffi-2.1.1-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:75f80557d1389eddbd0de2681f6a390a0c5338c31ddaa821381c203fc3fd50d9"}, + {file = "cffi-2.1.1-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:194cffa889098ced9976c3fc6340305e43f6303657d298da55366907c05c22d6"}, + {file = "cffi-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5bb4e7ea95dcd6a014a6fef62e62467d67d8e582326443f3d68e71d6320a9fcf"}, + {file = "cffi-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:3d22a20b1fb1632cc72c22f95f7b0d2961c3e1c235f245ba4c606c4771035659"}, + {file = "cffi-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1dea0e4d7d4f11f619fe8c1d76caf49e24405b4b5743c0e3be16a500ecd930c9"}, + {file = "cffi-2.1.1-cp310-cp310-win32.whl", hash = "sha256:7ce713ace7c0e4520535b42b77eaa742c16dab813978064913e5a3cf82973b41"}, + {file = "cffi-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:a48d62ab9d6f4f98c983223a547af44be6ca3691074c31cecced6facd3ba2dc1"}, + {file = "cffi-2.1.1-cp311-cp311-macosx_10_15_x86_64.whl", hash = "sha256:c8d2c9fd1f2d16f780d15127abb050d13d1a76c03a4bd87d7e4980e45e511e12"}, + {file = "cffi-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:398aff33cee2767e3e781d2554c54bd0dff386bb437581e0d8011fde1a942ec1"}, + {file = "cffi-2.1.1-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:154852545011f779917b11c78db2358d095da62a9a172b78ad0a583ee5adc0d0"}, + {file = "cffi-2.1.1-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3311ed60d36f83378794e1009ac6258bafbf81f7888b4caa7b35a521e3f95813"}, + {file = "cffi-2.1.1-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6e192623c49c94421616a5778fba35cf0d5a8d000650c1967ef4448ee5cdd990"}, + {file = "cffi-2.1.1-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a6e721d4b0e45d5b65e87534470e67b18dcd092c83f68fba09f152b9cbc061af"}, + {file = "cffi-2.1.1-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:34e261f78cb6ceaaa36f42f2613f4380d94d9c759a9c73c769ee6e0247364632"}, + {file = "cffi-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7225e4514edb64eb6740324353e0da0711954fd8d7da4576755b1c6e09b697cd"}, + {file = "cffi-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:df913725b79db7bcf03448f36b7bf8815363417d5b58deecf9305e3e30f0f21a"}, + {file = "cffi-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f5cfbc5fe74540d335175b656c725d74d90e3730c626d92575eea35029d9afaa"}, + {file = "cffi-2.1.1-cp311-cp311-win32.whl", hash = "sha256:f8ec5e643a9a937f64e1999eb9f75d072263751912dc5cd06d3c85f8f44be7c3"}, + {file = "cffi-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:42f6930c31dc7f50732c9ae793c2786c7b6b044195967bbdde40bb9be81c4cc0"}, + {file = "cffi-2.1.1-cp311-cp311-win_arm64.whl", hash = "sha256:c7659f22557c5a0bc4855cd635f55edec690cc008a40768527762cb9fb263455"}, + {file = "cffi-2.1.1-cp312-cp312-macosx_10_15_x86_64.whl", hash = "sha256:c8c69575568085ba0b1b10c0249d779a214aea6f6522e949a0fc9fb0fcb449d0"}, + {file = "cffi-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:f81b3b8f3d4e343550fa4baa0e479bba9f2d29ce9c2e9b51d1ce1718d7442fcf"}, + {file = "cffi-2.1.1-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:811bd1e21d32de12efca32393a0ab3f5133b54fce9bd44b8bd77ab07da14bf6a"}, + {file = "cffi-2.1.1-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:68e62fe11f30d5ca8289242866f0a5291402d8529ca2178ab8afc5c9694ae890"}, + {file = "cffi-2.1.1-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:4a7c934f7360e8cd64fe9efadcbd10c7c6364f531e432b9a4bf5ccbc9e0e8b50"}, + {file = "cffi-2.1.1-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:3143d81e29e1e20a9ce10901ec369012947876596f75a222235965f2b7ae832e"}, + {file = "cffi-2.1.1-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c1453022f490d2459a11819d83ad1d586e9ff65a12ac3e705ffebd46d3685dcf"}, + {file = "cffi-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:208f941bb9d18e768138677f0a6d2ce01f590df56043dda1df1535ac57c88517"}, + {file = "cffi-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:210019b6c7cf07f081b4c54635c8cf744377001350e29cc0f81c4377b4797735"}, + {file = "cffi-2.1.1-cp312-cp312-win32.whl", hash = "sha256:046bfc24911b37851ee1b51aab8bffe713d89c68c6a057b09484ce9fd5f69b4e"}, + {file = "cffi-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:f53e442b08449d42821fa4a4fba000095af9f62742a500f978a9f557ec44339a"}, + {file = "cffi-2.1.1-cp312-cp312-win_arm64.whl", hash = "sha256:7bde5e4cc5c10140859842b9d383af292b22639a4dffb725314baf45968cef80"}, + {file = "cffi-2.1.1-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:b5bdfd1c873d4e093aabc0ca84c4ca6dbc4f752afb5c86f146d9742580c9da2e"}, + {file = "cffi-2.1.1-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:31348097ff5bbe827ccc41795d4dd099d9f0625e7def00ee653c137a490c2a6c"}, + {file = "cffi-2.1.1-cp313-cp313-macosx_10_15_x86_64.whl", hash = "sha256:9d2055050ea716bd38b7f7f1579c275386646b4894c155a3e2f3cd62ed41b7c6"}, + {file = "cffi-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:19ee6127ee34de7d83ce3d371ebc5ed91addbdcc39f9ab15ce4eb35a4e534971"}, + {file = "cffi-2.1.1-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:6a8dddef476fab96d066d578fc88526767b836ab5ab21754e1d5bf3879c31c7c"}, + {file = "cffi-2.1.1-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:f16c709686a78c727bbbf059f92b0bf41c6fc60deec706d2dc19f529175a6125"}, + {file = "cffi-2.1.1-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:fcd22650c908d7b7da162bbfaab594a1227a15d1643a98c68b122ac642fa2264"}, + {file = "cffi-2.1.1-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:aa9511c62d14da7aacc9b4bf51f3f697a621e83b2d6919008243c3aad168eea3"}, + {file = "cffi-2.1.1-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:a931079504ecc49efed7744c476a5c343a92fabf66dec2db95edb1b2fdc770e2"}, + {file = "cffi-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a2d7755bef5a12ed488f4ef1f1b69ee9191d7396083b755a5d2295f6edb4768b"}, + {file = "cffi-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e0bcb7e0f677f543555d2adff3bf19c05f66cdb4796e5ff602442ab2fe3c4ef7"}, + {file = "cffi-2.1.1-cp313-cp313-win32.whl", hash = "sha256:334644fbac4eff73d985a17a91226df55d0f394160c4cfb880e084c8f7161cac"}, + {file = "cffi-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:1aa5645c30469b09530c4ebca77ebf8f17618293c58f8549cb1a543a50236e7d"}, + {file = "cffi-2.1.1-cp313-cp313-win_arm64.whl", hash = "sha256:63bbfd5ded17c4840ac07cd8f1c21ba9d9708141f840b324f422f41b207e3973"}, + {file = "cffi-2.1.1-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7dbb61fe3a7699468030f71bbe5f8a0e326a151daa91beb11a6fc1f980c55e1c"}, + {file = "cffi-2.1.1-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:f24fb43132a4c6b4cb4eb029492919b2db645be6808d738f244fd146c03c32cb"}, + {file = "cffi-2.1.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:d28630f5854ab07ab1fd4aba756de52326c82e6be15d414b12793f1975048b54"}, + {file = "cffi-2.1.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:661c298b4821edebead0c91edd2b00374d67ad7c5a1f7a91d4442633b79d6a72"}, + {file = "cffi-2.1.1-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:58acb8ab8e295e6c5ea12f888cbb13cf21511ef2a3303a23f4325c29d17fe5c1"}, + {file = "cffi-2.1.1-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:456a61fa52d579ebf9df2e9552ead5129855dbaff6c1e5a9b1bc408809bdc062"}, + {file = "cffi-2.1.1-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a4f00aa42f75d6e4595e8866e748cc1705adc0cddfeb2ca86d0d03993d63ba03"}, + {file = "cffi-2.1.1-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:b0431303acaea1089ad4b3e9ce4e6518193def1118d4073ca848635ee4ea2e96"}, + {file = "cffi-2.1.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:64faea20f4e2613363a1a9b9c7dd73058f3ecd00133a511e72ad7c511658f527"}, + {file = "cffi-2.1.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5c58fe613dc5e5336357eff555824a314d8e43282600435c8d1cb6a7a2fedd13"}, + {file = "cffi-2.1.1-cp314-cp314-win32.whl", hash = "sha256:1a18a57b58cfb21fc28d72e876acf10eaed67a1ed96226f92af4df681d571c4c"}, + {file = "cffi-2.1.1-cp314-cp314-win_amd64.whl", hash = "sha256:3222ba5d678f80a030e6afbcc33dc1ae5cb45facabb61cee2c7016b8432fde48"}, + {file = "cffi-2.1.1-cp314-cp314-win_arm64.whl", hash = "sha256:ab36d55f9ed2d067327667c2fea18dda018eb628dd6347aa01dda6cf1f5d3836"}, + {file = "cffi-2.1.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:7750c6449dff7864bb9bb27ddfb0267756189201a3afc911d82b3caacd70dfc3"}, + {file = "cffi-2.1.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:0beceaabe56af686895136a2de78db54ecd8e4046b236b8fd6d6cb61389e9bf2"}, + {file = "cffi-2.1.1-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:49cbc70e6542d4ccccb936558d1064a8012541e78f821f955cff24e357776c94"}, + {file = "cffi-2.1.1-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:e2d65b31f36619cda3999b78b2aa9632e76b78448e7a56fc4240824200e7c4fc"}, + {file = "cffi-2.1.1-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:28907ab9bfb6aa13184cfc17c6b8e1023c5ab6fd7076d8c20a35e59fe04f8f29"}, + {file = "cffi-2.1.1-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:51b31d1c98274844cfd7838ce00bfc27c7423a4dc00fc0772fc3331c2cc90676"}, + {file = "cffi-2.1.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:5e7cecbaadb83884793e05828cee59b210b24583b9c7425d0ba6a754fe22eb4e"}, + {file = "cffi-2.1.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:25792eac27877609e7bb06d42ff88278a6624fff2ba9bbb523c09616b117e80f"}, + {file = "cffi-2.1.1-cp314-cp314t-win32.whl", hash = "sha256:8ef53b2de9bcb9197d31854256575d59dbac0cba72ac627bb291ef5eceb74be4"}, + {file = "cffi-2.1.1-cp314-cp314t-win_amd64.whl", hash = "sha256:616f097f2fe415bc92a247f02e11f634e1f9e9a83d327e3c915c15089c87869e"}, + {file = "cffi-2.1.1-cp314-cp314t-win_arm64.whl", hash = "sha256:ad2c86c495b899d862ea0f4b42891b8713a3bd45dd4105c7fd51c2a72f39f3a5"}, + {file = "cffi-2.1.1-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:dddad92b554513a31f272570678ba307fb9f618f05e3d4a5eacafff9eae03e1d"}, + {file = "cffi-2.1.1-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:da0e573f9f97159390c89d9f1a9e41908b66d408cc5b58d08cf3847d844c531b"}, + {file = "cffi-2.1.1-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:fb92203a88b3d3053034db775110081c49d28be6551923805e039924093761e4"}, + {file = "cffi-2.1.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:2ae64be792b8966f2c69538199728b290e34726562896df1e5dc8ffd8d8188e8"}, + {file = "cffi-2.1.1-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:507a24c282e0f42f8ed737cf048572cbf580468da5555764a8331735e9c736b6"}, + {file = "cffi-2.1.1-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:246fa40ce8645a614ff682e0b70f37134e460eaf93a775e0cbe3cca585a67a80"}, + {file = "cffi-2.1.1-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:471cee653ae88de62096552e6d24ccb4a5adb8c8c9f10b5054d0122c15bf2779"}, + {file = "cffi-2.1.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:aeae0e330c9f6acd681f647d46cefd30c29f93e3392882e792e82080c9691399"}, + {file = "cffi-2.1.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:42a494cee34437f05546455144f2b5d9ac09b1face62bcfce597d2e521066688"}, + {file = "cffi-2.1.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:cc572dace3f60ef98d7b12ff411d20f5362feb31a0439eab0085bbfd349982d7"}, + {file = "cffi-2.1.1-cp315-cp315-win32.whl", hash = "sha256:4f42141fc14250de6dde5ee7ea4432be017252d91f19c5ad043c084cea629cac"}, + {file = "cffi-2.1.1-cp315-cp315-win_amd64.whl", hash = "sha256:e6e8cff14d6fb0be70a09c0bdc58096f501952d04624ebf867e0e56da2df8960"}, + {file = "cffi-2.1.1-cp315-cp315-win_arm64.whl", hash = "sha256:27350daa11d4f10c540e6e89dada4c54feb7256ad03e9a4dc075ebad7ba360d1"}, + {file = "cffi-2.1.1-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c26608d2222fb1e94487e4a387d85f13eb55d5ed725cb25a0c589ac4ee60e7bc"}, + {file = "cffi-2.1.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:4be96343e422f2dfcd12ab5c9f5aebe03f82f737c6bffeca6830b3875cb44aab"}, + {file = "cffi-2.1.1-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:937c0052c05a31ca1daf18de3158eed4dbfcb9cc107adbea227728d647be701e"}, + {file = "cffi-2.1.1-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:df423d40ee8654634421812bc3b196da3f9bd7d32929da813f8394c4348a5358"}, + {file = "cffi-2.1.1-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:a730a083190634c65cca36ba5f489531576ebd79bcd5c8e172130f6453127231"}, + {file = "cffi-2.1.1-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:363e05fa78e15116c3c32c210ee36884fd6b9afa6d440e47112c3bd511d64cb6"}, + {file = "cffi-2.1.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:770de9db11e84213beec501cfcaa013b019820ca881e03344dea5844f7876d94"}, + {file = "cffi-2.1.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:7da0c5eff80f0197f3b3d1232ec5a682a9325f4ae9016a78f5f5ca35f9ced1f5"}, + {file = "cffi-2.1.1-cp315-cp315t-win32.whl", hash = "sha256:06c72bb76605a4b0cd0aad6930b69d4baf7dd5d806cfc409b824191099700e66"}, + {file = "cffi-2.1.1-cp315-cp315t-win_amd64.whl", hash = "sha256:d9c275eaacd24aa73f94ffd6de08fc3f932424d8b6c376f4bed7cde376fe7bc3"}, + {file = "cffi-2.1.1-cp315-cp315t-win_arm64.whl", hash = "sha256:d18e5ac0f2f03f4f518d3e23db0f0cad7faa1da8620e9c09461d443bbf6e6692"}, + {file = "cffi-2.1.1.tar.gz", hash = "sha256:dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be"}, ] markers = {dev = "platform_python_implementation != \"PyPy\""} @@ -748,285 +795,328 @@ files = [ [[package]] name = "charset-normalizer" -version = "3.4.7" +version = "3.5.2" description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." optional = false python-versions = ">=3.7" groups = ["main", "dev", "docs"] files = [ - {file = "charset_normalizer-3.4.7-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cdd68a1fb318e290a2077696b7eb7a21a49163c455979c639bf5a5dcdc46617d"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e17b8d5d6a8c47c85e68ca8379def1303fd360c3e22093a807cd34a71cd082b8"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:511ef87c8aec0783e08ac18565a16d435372bc1ac25a91e6ac7f5ef2b0bff790"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:007d05ec7321d12a40227aae9e2bc6dca73f3cb21058999a1df9e193555a9dcc"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cf29836da5119f3c8a8a70667b0ef5fdca3bb12f80fd06487cfa575b3909b393"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_armv7l.whl", hash = "sha256:12d8baf840cc7889b37c7c770f478adea7adce3dcb3944d02ec87508e2dcf153"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:d560742f3c0d62afaccf9f41fe485ed69bd7661a241f86a3ef0f0fb8b1a397af"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b14b2d9dac08e28bb8046a1a0434b1750eb221c8f5b87a68f4fa11a6f97b5e34"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:bc17a677b21b3502a21f66a8cc64f5bfad4df8a0b8434d661666f8ce90ac3af1"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:750e02e074872a3fad7f233b47734166440af3cdea0add3e95163110816d6752"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:4e5163c14bffd570ef2affbfdd77bba66383890797df43dc8b4cc7d6f500bf53"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6ed74185b2db44f41ef35fd1617c5888e59792da9bbc9190d6c7300617182616"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:94e1885b270625a9a828c9793b4d52a64445299baa1fea5a173bf1d3dd9a1a5a"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win32.whl", hash = "sha256:6785f414ae0f3c733c437e0f3929197934f526d19dfaa75e18fdb4f94c6fb374"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win_amd64.whl", hash = "sha256:6696b7688f54f5af4462118f0bfa7c1621eeb87154f77fa04b9295ce7a8f2943"}, - {file = "charset_normalizer-3.4.7-cp310-cp310-win_arm64.whl", hash = "sha256:66671f93accb62ed07da56613636f3641f1a12c13046ce91ffc923721f23c008"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:7641bb8895e77f921102f72833904dcd9901df5d6d72a2ab8f31d04b7e51e4e7"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:202389074300232baeb53ae2569a60901f7efadd4245cf3a3bf0617d60b439d7"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:30b8d1d8c52a48c2c5690e152c169b673487a2a58de1ec7393196753063fcd5e"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:532bc9bf33a68613fd7d65e4b1c71a6a38d7d42604ecf239c77392e9b4e8998c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2fe249cb4651fd12605b7288b24751d8bfd46d35f12a20b1ba33dea122e690df"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_armv7l.whl", hash = "sha256:65bcd23054beab4d166035cabbc868a09c1a49d1efe458fe8e4361215df40265"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:08e721811161356f97b4059a9ba7bafb23ea5ee2255402c42881c214e173c6b4"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e060d01aec0a910bdccb8be71faf34e7799ce36950f8294c8bf612cba65a2c9e"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:38c0109396c4cfc574d502df99742a45c72c08eff0a36158b6f04000043dbf38"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:1c2a768fdd44ee4a9339a9b0b130049139b8ce3c01d2ce09f67f5a68048d477c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:1a87ca9d5df6fe460483d9a5bbf2b18f620cbed41b432e2bddb686228282d10b"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:d635aab80466bc95771bb78d5370e74d36d1fe31467b6b29b8b57b2a3cd7d22c"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ae196f021b5e7c78e918242d217db021ed2a6ace2bc6ae94c0fc596221c7f58d"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win32.whl", hash = "sha256:adb2597b428735679446b46c8badf467b4ca5f5056aae4d51a19f9570301b1ad"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win_amd64.whl", hash = "sha256:8e385e4267ab76874ae30db04c627faaaf0b509e1ccc11a95b3fc3e83f855c00"}, - {file = "charset_normalizer-3.4.7-cp311-cp311-win_arm64.whl", hash = "sha256:d4a48e5b3c2a489fae013b7589308a40146ee081f6f509e047e0e096084ceca1"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:eca9705049ad3c7345d574e3510665cb2cf844c2f2dcfe675332677f081cbd46"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6178f72c5508bfc5fd446a5905e698c6212932f25bcdd4b47a757a50605a90e2"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e1421b502d83040e6d7fb2fb18dff63957f720da3d77b2fbd3187ceb63755d7b"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:edac0f1ab77644605be2cbba52e6b7f630731fc42b34cb0f634be1a6eface56a"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5649fd1c7bade02f320a462fdefd0b4bd3ce036065836d4f42e0de958038e116"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_armv7l.whl", hash = "sha256:203104ed3e428044fd943bc4bf45fa73c0730391f9621e37fe39ecf477b128cb"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:298930cec56029e05497a76988377cbd7457ba864beeea92ad7e844fe74cd1f1"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:708838739abf24b2ceb208d0e22403dd018faeef86ddac04319a62ae884c4f15"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:0f7eb884681e3938906ed0434f20c63046eacd0111c4ba96f27b76084cd679f5"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:4dc1e73c36828f982bfe79fadf5919923f8a6f4df2860804db9a98c48824ce8d"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:aed52fea0513bac0ccde438c188c8a471c4e0f457c2dd20cdbf6ea7a450046c7"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:fea24543955a6a729c45a73fe90e08c743f0b3334bbf3201e6c4bc1b0c7fa464"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bb6d88045545b26da47aa879dd4a89a71d1dce0f0e549b1abcb31dfe4a8eac49"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win32.whl", hash = "sha256:2257141f39fe65a3fdf38aeccae4b953e5f3b3324f4ff0daf9f15b8518666a2c"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win_amd64.whl", hash = "sha256:5ed6ab538499c8644b8a3e18debabcd7ce684f3fa91cf867521a7a0279cab2d6"}, - {file = "charset_normalizer-3.4.7-cp312-cp312-win_arm64.whl", hash = "sha256:56be790f86bfb2c98fb742ce566dfb4816e5a83384616ab59c49e0604d49c51d"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:f496c9c3cc02230093d8330875c4c3cdfc3b73612a5fd921c65d39cbcef08063"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0ea948db76d31190bf08bd371623927ee1339d5f2a0b4b1b4a4439a65298703c"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a277ab8928b9f299723bc1a2dabb1265911b1a76341f90a510368ca44ad9ab66"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:3bec022aec2c514d9cf199522a802bd007cd588ab17ab2525f20f9c34d067c18"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e044c39e41b92c845bc815e5ae4230804e8e7bc29e399b0437d64222d92809dd"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_armv7l.whl", hash = "sha256:f495a1652cf3fbab2eb0639776dad966c2fb874d79d87ca07f9d5f059b8bd215"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e712b419df8ba5e42b226c510472b37bd57b38e897d3eca5e8cfd410a29fa859"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:7804338df6fcc08105c7745f1502ba68d900f45fd770d5bdd5288ddccb8a42d8"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:481551899c856c704d58119b5025793fa6730adda3571971af568f66d2424bb5"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f59099f9b66f0d7145115e6f80dd8b1d847176df89b234a5a6b3f00437aa0832"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:f59ad4c0e8f6bba240a9bb85504faa1ab438237199d4cce5f622761507b8f6a6"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:3dedcc22d73ec993f42055eff4fcfed9318d1eeb9a6606c55892a26964964e48"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:64f02c6841d7d83f832cd97ccf8eb8a906d06eb95d5276069175c696b024b60a"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win32.whl", hash = "sha256:4042d5c8f957e15221d423ba781e85d553722fc4113f523f2feb7b188cc34c5e"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win_amd64.whl", hash = "sha256:3946fa46a0cf3e4c8cb1cc52f56bb536310d34f25f01ca9b6c16afa767dab110"}, - {file = "charset_normalizer-3.4.7-cp313-cp313-win_arm64.whl", hash = "sha256:80d04837f55fc81da168b98de4f4b797ef007fc8a79ab71c6ec9bc4dd662b15b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:c36c333c39be2dbca264d7803333c896ab8fa7d4d6f0ab7edb7dfd7aea6e98c0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1c2aed2e5e41f24ea8ef1590b8e848a79b56f3a5564a65ceec43c9d692dc7d8a"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:54523e136b8948060c0fa0bc7b1b50c32c186f2fceee897a495406bb6e311d2b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:715479b9a2802ecac752a3b0efa2b0b60285cf962ee38414211abdfccc233b41"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:bd6c2a1c7573c64738d716488d2cdd3c00e340e4835707d8fdb8dc1a66ef164e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_armv7l.whl", hash = "sha256:c45e9440fb78f8ddabcf714b68f936737a121355bf59f3907f4e17721b9d1aae"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3534e7dcbdcf757da6b85a0bbf5b6868786d5982dd959b065e65481644817a18"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e8ac484bf18ce6975760921bb6148041faa8fef0547200386ea0b52b5d27bf7b"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:a5fe03b42827c13cdccd08e6c0247b6a6d4b5e3cdc53fd1749f5896adcdc2356"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2d6eb928e13016cea4f1f21d1e10c1cebd5a421bc57ddf5b1142ae3f86824fab"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e74327fb75de8986940def6e8dee4f127cc9752bee7355bb323cc5b2659b6d46"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:d6038d37043bced98a66e68d3aa2b6a35505dc01328cd65217cefe82f25def44"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:7579e913a5339fb8fa133f6bbcfd8e6749696206cf05acdbdca71a1b436d8e72"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win32.whl", hash = "sha256:5b77459df20e08151cd6f8b9ef8ef1f961ef73d85c21a555c7eed5b79410ec10"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win_amd64.whl", hash = "sha256:92a0a01ead5e668468e952e4238cccd7c537364eb7d851ab144ab6627dbbe12f"}, - {file = "charset_normalizer-3.4.7-cp314-cp314-win_arm64.whl", hash = "sha256:67f6279d125ca0046a7fd386d01b311c6363844deac3e5b069b514ba3e63c246"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:effc3f449787117233702311a1b7d8f59cba9ced946ba727bdc329ec69028e24"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:fbccdc05410c9ee21bbf16a35f4c1d16123dcdeb8a1d38f33654fa21d0234f79"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:733784b6d6def852c814bce5f318d25da2ee65dd4839a0718641c696e09a2960"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:a89c23ef8d2c6b27fd200a42aa4ac72786e7c60d40efdc76e6011260b6e949c4"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6c114670c45346afedc0d947faf3c7f701051d2518b943679c8ff88befe14f8e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_armv7l.whl", hash = "sha256:a180c5e59792af262bf263b21a3c49353f25945d8d9f70628e73de370d55e1e1"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3c9a494bc5ec77d43cea229c4f6db1e4d8fe7e1bbffa8b6f0f0032430ff8ab44"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8d828b6667a32a728a1ad1d93957cdf37489c57b97ae6c4de2860fa749b8fc1e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:cf1493cd8607bec4d8a7b9b004e699fcf8f9103a9284cc94962cb73d20f9d4a3"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:0c96c3b819b5c3e9e165495db84d41914d6894d55181d2d108cc1a69bfc9cce0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:752a45dc4a6934060b3b0dab47e04edc3326575f82be64bc4fc293914566503e"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:8778f0c7a52e56f75d12dae53ae320fae900a8b9b4164b981b9c5ce059cd1fcb"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:ce3412fbe1e31eb81ea42f4169ed94861c56e643189e1e75f0041f3fe7020abe"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win32.whl", hash = "sha256:c03a41a8784091e67a39648f70c5f97b5b6a37f216896d44d2cdcb82615339a0"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win_amd64.whl", hash = "sha256:03853ed82eeebbce3c2abfdbc98c96dc205f32a79627688ac9a27370ea61a49c"}, - {file = "charset_normalizer-3.4.7-cp314-cp314t-win_arm64.whl", hash = "sha256:c35abb8bfff0185efac5878da64c45dafd2b37fb0383add1be155a763c1f083d"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:e5f4d355f0a2b1a31bc3edec6795b46324349c9cb25eed068049e4f472fb4259"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:16d971e29578a5e97d7117866d15889a4a07befe0e87e703ed63cd90cb348c01"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dca4bbc466a95ba9c0234ef56d7dd9509f63da22274589ebd4ed7f1f4d4c54e3"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e80c8378d8f3d83cd3164da1ad2df9e37a666cdde7b1cb2298ed0b558064be30"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36836d6ff945a00b88ba1e4572d721e60b5b8c98c155d465f56ad19d68f23734"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_armv7l.whl", hash = "sha256:bd9b23791fe793e4968dba0c447e12f78e425c59fc0e3b97f6450f4781f3ee60"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:aef65cd602a6d0e0ff6f9930fcb1c8fec60dd2cfcb6facaf4bdb0e5873042db0"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:82b271f5137d07749f7bf32f70b17ab6eaabedd297e75dce75081a24f76eb545"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_armv7l.whl", hash = "sha256:1efde3cae86c8c273f1eb3b287be7d8499420cf2fe7585c41d370d3e790054a5"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:c593052c465475e64bbfe5dbd81680f64a67fdc752c56d7a0ae205dc8aeefe0f"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_riscv64.whl", hash = "sha256:af21eb4409a119e365397b2adbaca4c9ccab56543a65d5dbd9f920d6ac29f686"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:84c018e49c3bf790f9c2771c45e9313a08c2c2a6342b162cd650258b57817706"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:dd915403e231e6b1809fe9b6d9fc55cf8fb5e02765ac625d9cd623342a7905d7"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-win32.whl", hash = "sha256:320ade88cfb846b8cd6b4ddf5ee9e80ee0c1f52401f2456b84ae1ae6a1a5f207"}, - {file = "charset_normalizer-3.4.7-cp38-cp38-win_amd64.whl", hash = "sha256:1dc8b0ea451d6e69735094606991f32867807881400f808a106ee1d963c46a83"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:177a0ba5f0211d488e295aaf82707237e331c24788d8d76c96c5a41594723217"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6e0d51f618228538a3e8f46bd246f87a6cd030565e015803691603f55e12afb5"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:14265bfe1f09498b9d8ec91e9ec9fa52775edf90fcbde092b25f4a33d444fea9"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:87fad7d9ba98c86bcb41b2dc8dbb326619be2562af1f8ff50776a39e55721c5a"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f22dec1690b584cea26fade98b2435c132c1b5f68e39f5a0b7627cd7ae31f1dc"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_armv7l.whl", hash = "sha256:d61f00a0869d77422d9b2aba989e2d24afa6ffd552af442e0e58de4f35ea6d00"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:6370e8686f662e6a3941ee48ed4742317cafbe5707e36406e9df792cdb535776"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:a6c5863edfbe888d9eff9c8b8087354e27618d9da76425c119293f11712a6319"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:ed065083d0898c9d5b4bbec7b026fd755ff7454e6e8b73a67f8c744b13986e24"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:2cd4a60d0e2fb04537162c62bbbb4182f53541fe0ede35cdf270a1c1e723cc42"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:813c0e0132266c08eb87469a642cb30aaff57c5f426255419572aaeceeaa7bf4"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:07d9e39b01743c3717745f4c530a6349eadbfa043c7577eef86c502c15df2c67"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:c0f081d69a6e58272819b70288d3221a6ee64b98df852631c80f293514d3b274"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win32.whl", hash = "sha256:8751d2787c9131302398b11e6c8068053dcb55d5a8964e114b6e196cf16cb366"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win_amd64.whl", hash = "sha256:12a6fff75f6bc66711b73a2f0addfc4c8c15a20e805146a02d147a318962c444"}, - {file = "charset_normalizer-3.4.7-cp39-cp39-win_arm64.whl", hash = "sha256:bb8cc7534f51d9a017b93e3e85b260924f909601c3df002bcdb58ddb4dc41a5c"}, - {file = "charset_normalizer-3.4.7-py3-none-any.whl", hash = "sha256:3dce51d0f5e7951f8bb4900c257dad282f49190fdbebecd4ba99bcc41fef404d"}, - {file = "charset_normalizer-3.4.7.tar.gz", hash = "sha256:ae89db9e5f98a11a4bf50407d4363e7b09b31e55bc117b4f7d80aab97ba009e5"}, -] - -[[package]] -name = "click" -version = "8.4.1" -description = "Composable command line interface toolkit" -optional = false -python-versions = ">=3.10" -groups = ["main", "docs"] -files = [ - {file = "click-8.4.1-py3-none-any.whl", hash = "sha256:482be17c6991b8c19c5429a1e995d9b0efdbb63172824c41f99965dc0ade8ec2"}, - {file = "click-8.4.1.tar.gz", hash = "sha256:918b5633eddf6b41c32d4f454bf0de810065c74e3f7dbf8ee5452f8be88d3e96"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:195c26fb65950f8fce54e26349852b7bdd7c5f120aeefbcc440b8a20faaed4a3"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9373ad13ef0d2c0fb761e04e55bfdee5a08b52cef2c882c8fbe9935b1517152e"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ddf19c062bea7a0cc80f519243d2c01dd091be0cf952a0750d4ad576709559f5"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3d14b50de6bf4d0edf857a9386836846f982b8f524e188e2e68b96d702bcf4aa"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:28a15fdad492a99b6eccfaaed66ef3f74050680545ea61ec8b2f4c538f1f1320"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a893cc101149f80a653f82062ebc95b34525a2614382e1da5458fe7c6997249"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:619799369eeef6366ed3e8755a5670f4f2f0fb6b30a0fd7264dc0fdc2357058e"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:447441e76ec720b15e64418d32e092297340387053047c7c694f579efb0ee1d9"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:62588a277bfb59def052abd940703fa35107152bf479781a878617d60faf8fb5"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:44bd4fbb29dfbeba60e7d2bd000c59e4b21ddb3cc53912b14048d37092706d7c"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:30fcd120b732aa79317f08dee04d7de0847822e4cf7ee0e9f445bb958832252c"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:50e3adfb96fc189eb27b1cf62d3b598b89b4bb0420d93a3d3e42e137409011be"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b736353c0a625bbd5fcec108576e2385db3496f4f771f785ff32e108d3c3bc45"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-win32.whl", hash = "sha256:f5833ad231be5eb6553de524a70f48d71b2c8563101750531e0b80184e175cd4"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-win_amd64.whl", hash = "sha256:1461ac396c4fdb983a675f20aa555624f0ee18ac83d832b9244ffff3d8055275"}, + {file = "charset_normalizer-3.5.2-cp310-cp310-win_arm64.whl", hash = "sha256:c6708715abcf3c73b99508253e961a9967f02fe536532834149574eda6de0d1c"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:3d21b8b13c7592db2ac5e544a6d83187b995257472b0c9e8351b6d507ae37ed6"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d760fe2a4d7c3b226cb9026d6a842868d52a7901bd98420e1baf14e80da85cf5"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c9790464842f85f437dbbb54417eda1e0e6bfc52dd8d22d6fd1c994b73b2dc74"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:4685902cf26edf013ed7a3da0f426ebba7a00ebb9541386d835afbf002c11cab"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4495c5002a7b28557e7e222e77e0b661183e432b7d6d2e788101e3f240e05b8c"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:211d5a3eb6af8f513b8d4ca19a8c1b7accab1b5f0d3175f9826b03c1a920dc1f"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ef4fcbf3327382cd4c9f540babd61248208af7b93eec4de397b4d5f58a09e288"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:bd16aabe4a02a297c23417aa17ac6299dbd8c49f673bcd645b4929b11f5a4400"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:fb9e68df06293761f9fe66ade60a9bc6d0f5e42b8acf2939a9158af86ab0e5bd"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:59f63901b0031c3136cf64704dcb21de0bbae62ce2c9529bc39d27665463de37"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:304d5463e65a35d7bb0850550e0780395395f6fcf452f04db7d5ca7cecc425ac"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:9cf9b1a857e25c4baceeb3624e92a56df3668f398c4acba74e174d81fb4d1d3a"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:114e4d0c92d618409ed82a99e22b5c5e768fe995f2973f78265f4524f49d4640"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-win32.whl", hash = "sha256:2625388c6c754520c37abaf3b41eb34d1cc4a373f457898f08606c8e362b891d"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-win_amd64.whl", hash = "sha256:87e50a3e7cb90af586b6c5faf23e302a970415ac73bd7bd90a515a04b427ef96"}, + {file = "charset_normalizer-3.5.2-cp311-cp311-win_arm64.whl", hash = "sha256:254eb48b9fa5ee9898a3c445825a1f340fe53712a098904b39b0bddba8ea3cb1"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:ed2a239c0ea213acc1908150a3037257083c7c083128f1a4cec2ec4b97dca491"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b91363207bd9dc966a691e959bb47f64b30f7ac4b072be9968b366982f7db77c"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:38a873987f3be698494da8b2e3085e29da02da7b633dce73e79c699a113d7bf0"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:355ad8011081dec5412240c087a9a0c9d4d5039f3ed11a3f13e18c2b29b56c51"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:ee21e28f0430bd6dc9086c6e525d5e818a44a5ad19720c8a0ef766792f3eb5e5"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3d31298449090ab8d47b7b1b2a555ff73cac7ed438a08b7ac160980c7ebed649"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5cde776b7cc66e4f6c99612cea4aa7269aa65863f7a15841b2c264f103822f4e"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ae4f5fea5b8b8ccff88238cc8569303e5ee95efae67fa62922a311397a71f346"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:f7d486c83842422badd511868fd8a9a20e9407ace71564b6af47ce7e60a336c1"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:11a4d68a6ecda3292cb1e50239e111543ba5d709bb62a6b4ea1afcfa729d8875"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d6734d2ef8a50fbf8445c139477da401f50d62a0606bf00e20ec6d87773fefb1"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:a815775b6c38d4e0ff7bcffbeba67feded90202bb6a226b8dd35f1c855217413"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:23851fb4e1b85ed3f6c2a27b777cdfe2e19fb5b38429a8faf38c7542b7665869"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-win32.whl", hash = "sha256:db19d07e2e0129e974a0e65d0064fc222a446cd5122c2fd4184d2af9fc734a9e"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:780fbe7cab297b81dad9fb8dc5eb003c0468ffb0d9e5f65068c53a34661a96bc"}, + {file = "charset_normalizer-3.5.2-cp312-cp312-win_arm64.whl", hash = "sha256:e2af3aad578aa6bd1384bcf4750fc285e5a9de53f40b7d41e5a0bf748edeb2b3"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:ed905975ab14056a2e5eb1c376cb2e1ebc5396baf84163939c518556fccde9f5"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-android_24_x86_64.whl", hash = "sha256:a66c3bc5ab1f0ff2164fc9965ddd611ff0802173f4b9d24554c563f6ab7e1d6e"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:d2374b62878abb00cd8309b32af6c0b715cd02dec0ca74ef12e5069bdc64144a"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:d376bbd28b3a8999db1a103b3b388aee6f1ddeb3e51bc2172993efdcd86e064d"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:6045373d5a89a5ec71afde535db987ca28e76dfa276c2d4c818265b375d4b055"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849df64e889b2e17230d58410a03dba311a65b163508fd33679b2b737d4b7858"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:15c44f7edfd477b06f517a5cc317fc1707edb9de2c865f43d4b6513907473234"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a89012d6d5476ee112d20d998570ed58df2260a852afb1758809cd6900411d21"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:0c951d5e6dd9c2ff60609476752bee49da4206adde960ebc247766937f72e718"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7218e8f32b0956cfcd048fd42d9d5779809745ca1d86113ca56f66e7ae1549c4"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a19a731138fc27d5682277d3b9df22855cea1239bce7fcec5f78f42ef2d1f3c3"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:62603db9a7caa0802eaa28c1c46fecd7b3a263a774069c24c3c28c302448721c"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:b6856554c4f44d79fc2307d5768854310a8f0096e501c75637542c82292b0429"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:1bc0baf5ef96b6ede57d47f4b8fe4d9d84019c3bfcbeb20a41edc6a6ee341f1f"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:56bc200a365efb37383b7852e4cc5898d3b2da5987289b543956cf8cad71018a"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2c9ad19a6cfcd5ea5c0d41161d22f9df1dcc277e9bef2751391334546a314c00"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e243bd13217235fc7290c621941c3f5cc8b66e4872495be821d7436ba2fb838d"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:a090bb2c68df85450502e3e20d665e3a5af9c65a84d6508ed477badd49166fd3"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-win32.whl", hash = "sha256:2b7b3bbfb4fe8ef40600792d762fbaa9057559f9d3fad209525b7a22b99e91fd"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:78456a747de8dc58360ffa581f30a002baf5aa28cb262536545e91f113ed7639"}, + {file = "charset_normalizer-3.5.2-cp313-cp313-win_arm64.whl", hash = "sha256:11912e4bb14baae7c5d8791aa55ba0a3a03ec6729073307b0f57270abaa713d3"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:1afb975bd5d68d5ce9f6b6d44fdf2f7e34b895a35e95708a7a91b20a3b51d187"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-android_24_x86_64.whl", hash = "sha256:bbbfc8e28816f19d7c0f1816664980c0a9875d01b27cdf8eedddb639d9e108ad"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:7967d08cf06dee78443b874f98c98036f624f3a4e73e11f9f64f5be4d25393cf"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:4c2b5031f63e331e3839b40aed2dd6f191e9c07edbde303e7876846ea1946995"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-macosx_10_15_universal2.whl", hash = "sha256:fcff63213e8e6e47770541a4607175404f47cbb3ebea7b6058cc82d524a0e424"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8d86d6fc60743dc916eb79e2eb1ec4818e21e427731543af40a3021851174a13"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a881931aa470808df94a8c380eed2bbbc76cd9dc622310f99665658c821eb6d"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8024d00c3faf3fc0c16e07a69f4405e8eac7cc0ab15f65fe6cf43827c4cf72b4"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:4d48f2d08b9de5864e2c8744d4461b862fb149a18274abc8b698c45975573438"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:34276fd796040bf0993ab33a369aa572e6979c7aab225a88893667ad8eac8f7a"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0521c5665880b33d603717defa76c094048900010897909952397feb3039da56"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:eff0ac9dbe711a4aee69bf04a83896aa9b85f19641264053a9f6d48573abb7dd"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:1503bccbeb36d5527790c3930327704c39af22de3112f1b1666a9f3ce15ee204"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:52aa6992700996af31f375de0c6bacd402b0097fe40b53c426b9f51a90ebabc7"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:e09a3942ecbdee5cce73ea9d42da82b81b72ac1bf031ce069b93b5adf4eac8cd"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_s390x.whl", hash = "sha256:c7c9ab723cde841fefb34efbad91e87f00a674b1fe1cd0784fde742bf2c154dc"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:ddc7dacc8ece3a182e7f15cb862d1fd616b46d076cb1ae9dd232b2c38b655874"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:ee43c17b173d46a3212baa6ead3ae258eeabdae48c263a01ccf0218c366dd655"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-win32.whl", hash = "sha256:4f87960d57feabfb618e4e0af6e7371645fa26a277860739d6e5d6e0012c92f0"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-win_amd64.whl", hash = "sha256:e4e81e09c1578b8df602e3db08b0b3ea0a6947ad612f52bf8dc5ea8d47691f0c"}, + {file = "charset_normalizer-3.5.2-cp314-cp314-win_arm64.whl", hash = "sha256:80d02b6f04e92601a081dd97b23d3128033098bff5d35d392ddcc0476ea11253"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-macosx_10_15_universal2.whl", hash = "sha256:dca9ab98072a5a54ebacebdc45f53e645336b320c667410b061be1ca588ae709"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f0aa869112ef88429ae17820d99c3dd9504c9e9c671d3c246f3d7442cb051084"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c0afc6800ba57ccc350374c5bd6150419915d95ce93cdbab2d783d75eaf30ecb"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7dcd882da75ef9adf94903b1e3b9419e8aa8fb4c7396822b834b9ef7fb96954f"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2e06a3a98f916dd41d27f3105e02e7a40181c98c94b9158733d03a6f80506c09"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6bd128f206a7752ae1f2ab6c61bf8a24ba28913a10df8b14c2637b973ff97a80"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c8f3d67aeaf55f017982b73683f0e7342ba2f6635a78f69ce89ebb26aa411e5c"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:fe9753dfee015c570d73df76f899f18444d41388bffcde097deba51c4fadbb9f"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:92888bb3187c5ba50500b00b3b310c9f2c651709d28036077680cb5255450a03"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:d008d90a7f2471519aef0c90dfbe73b3e6e4d5e66ac48e19154c17e89e98b604"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:31f3930700408d211f13378ccbe1c40845d8da54bd0681fac3a9b5aae81c7aa8"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_s390x.whl", hash = "sha256:2a925889534b3748302dae5dead07cc13480de1dac3aea80a941b729b471ef93"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f5ec61164adcec446f8969a3358ec3f9b26bbda3b9213e5586d219afa8df2915"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-win32.whl", hash = "sha256:598a11a2c7ebaa5334bf698bf29568c9c390abac6a154d8170fedecd1cea38c5"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-win_amd64.whl", hash = "sha256:7fdde2c9fd9e3eca40631e024664cf2584272cc8f96308cbe5fdfc930f51d8bc"}, + {file = "charset_normalizer-3.5.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d1befeed746d247c81127bb14de9dc3d30edb6e5976d34f83f86ed262b1d9105"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-macosx_10_15_universal2.whl", hash = "sha256:87475fabc8d9996fd9c27debb395e642e8c838d78a00b6e932227a0e06b81e26"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9409a8bf35cf78353942504b24a57de3d75b708997a1e4bd8db71ac8633ce364"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:498dc3188ca05a68231ac3fdbfc7f57eb67e1343c30e0fea17f8218c1599b253"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e242bb1c5e76e97dfa9e7f209a71e93a01d7f19ffdd5cfbb2e2d55b4f08f8ab0"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def79fa35ef0cef8d2accec024f4fdc7ead3012ff02f5215c783f39f03ef8cfc"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:3df041de8887954562c9b261cba85ca0e9ded74048daf125f45edcfaa4832229"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:04851f73ae72b8413dddadb16a49dfee95263553741fd42d546f7d66907e6be5"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:183b88127acdb4fabe59d951ab424faf1af7b63cdbb5f776186c1ea2ffcaed98"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:16fa0eccf81304b79c5cd87f9271c3b85dd9dd99245e4422ae9c0dd45e0f99d3"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:7441d755b7ab94f8d4eb3e43ec05482d760842fd263d003a99102d742cd835e2"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:ca403d7e4798f525fdfc78e258820419cbbd0f0ecbab9de7840e3c017cf6b8cf"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_s390x.whl", hash = "sha256:df29a0a7107f7011e77f4eebdddec4c7331e24d787a0b21a46d63bdf7445da95"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:f3c96f633825733f735c5a9cf21d21a257d8e1edf0b1cee0a064b9c424ca0f7d"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-win32.whl", hash = "sha256:281cb91036248400f4cc957495cccd44c275c2e0c5854f7e45ac5cf7dc193847"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-win_amd64.whl", hash = "sha256:89b53f3cda69831909888e0494f4fa0bcd3537e3e138dabeb620bd6ad946bae8"}, + {file = "charset_normalizer-3.5.2-cp315-cp315-win_arm64.whl", hash = "sha256:6be488a102b8cf28d0391d8c4ba7748938ae28b78ad901f8585520fca33ead1a"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-macosx_10_15_universal2.whl", hash = "sha256:915563965d418f986e7e145accc592eae9e1a1be3566ff98a05d7a9ec42a76e1"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:65cd72beeeca9d3aaea1201e5923859f308f952f9c71de93f06063c79f0f7a3b"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b7fd005a73d9e657273b7a10dc71a9e03c8fb9ee6999798d6918ce095b81ac7f"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e54da4baf05720032d527874d40b65fa4d7e5c6c6a43d0c3adbeffcaf275a2b3"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:124fbf1a8ff966d87ae05bb8bd45a71f966055ed8bba320d0c7cf450bc5f4d0e"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:28b4f0d66fb834ff90f28209ac7bce77868c45d8c93e26f906709d9b7c2e1af9"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:58ca3755ee7ff7f59b57789ec9833c9de9ea275405cdd240eda1f193112e398a"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:443eae2bf318abeaf6f15d785138f71fd6de770e99a92158b8b814265e079115"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:58f361dcbab699cf8f42db3f47c8e7fd1036f138c23a5d08de9fde5f425a730c"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:1b4cbc7c3491ccb4aa17fcd8165649d01cf39f76de1696da8631b5f71b85401d"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:ba0b1d2620edf869789c3879223f52bf2afc5d31b3cb47cc57b3a12c05e2aa9d"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_s390x.whl", hash = "sha256:5e2b6b57e9733d39f0c9fd3185efa6b8e29652c4cd8fe94180272cf6ed9a78c4"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:51cf45226a9b588d0d2b4880c62d686934b63ab0bd79ca23ab0e9762eb27441b"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-win32.whl", hash = "sha256:5fb29fb8cd1a46c27a1bf9613ad5ec2599310d46b4025d9556404a6b6a292800"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-win_amd64.whl", hash = "sha256:a192e2c40070d92c3ccf777e3a5c4ff515573cd2bb7ed0c537fdadbbec5bbf21"}, + {file = "charset_normalizer-3.5.2-cp315-cp315t-win_arm64.whl", hash = "sha256:749e97e1b32313717a565abbe321bc2190bc8b35f1a67e4cdbc7c56c8d8ffe58"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:4275811936e2f06feff5e598fb42a1b7ae852da8e39605211892b56b81a34efd"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:1c50fe28bbc2ced33386f298650d91218076c05420e6cbd790b913adc41659e7"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:d19fbd981a488e22cd04883659ca6b08f50b5974f9fd7c95655ef6a043e5893f"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0fed1d06615f022ee3b13caf5e8b180cfea32bb2c5aded8a9d44277afc040f93"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:838dcc90063569a0448120554591a1d6c4a4ffe11babf048908793154ab86ade"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:2ce45c6627b22c47e390bc91a41c3d13032192e699fa0bea96e9671b373d69b0"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0774bf9bf620249fee3e0b8b9fd3065de213be30f3aa94ce2494b3b638949e26"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:1db38f4c5496827c1a501846d64d14c3b80c7e6714e406cd7dc36a9899fa1011"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_armv7l.whl", hash = "sha256:304d8e4d493af723536393eee0c689eb7813f4a474c8b479dee63f1fdd98f621"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:9b7f416ff0978e2f2249330527f0ad6fa02f4932e6199692d3b52da2048c19e4"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:01077390b03f7988f11d700a2194e69b119741a86b1a638b1db88891e3eced8e"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_s390x.whl", hash = "sha256:7e841fb9010836c992c9f12fcbd43a831de93a5f726fc1ccd8ca1d0268c5014c"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:9cae88599c7219005d879f98e5ed53341e9a122af585e1091200358a3003d2a0"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-win32.whl", hash = "sha256:01b0c0d2262a9e28e8484a278c7e1b5d650e3ac8cf2683d2967e25899f208bdf"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-win_amd64.whl", hash = "sha256:9f56f72050826f63dcee7a7f55b0a77168cb3bfc553fd405e7f8f9ece75a4036"}, + {file = "charset_normalizer-3.5.2-cp37-abi3-win_arm64.whl", hash = "sha256:40ab6bffa02ae10a0581e6c198be7d2d8ca5c2a0c64e4ed3465d766df457573e"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:75a3ceed0724d625d64b86ca20aba182e4df462e04c2414fc941c0f523f06aac"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0891b9d3903c5571c03771ca669a4b0ec5618ca722a5c957d3d29cd4e5062848"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:fc14a032f813bf5fe624d991960ea83e9715adc27e4c1830a2361eb1d02ac341"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:8b2bfab86aa71ae13aa41a6a26aab338e0db2b8bc75434b05aea89e011ff35a4"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:9bde855991b7e362c146535e3136a50bfaffc0487d38b33ca7e5edefc6e23849"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:55ea99acb17b9325618de155a0cd6a2e8f5d10be008113e1d433bbb58db543b2"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:68eb192d85ab8e5f6ec69c2bc6ac0179fbf04a5ac1569d12fbef74883fe102d0"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:d913de495d90407cd859d263bee2e5d1a4ed3eb6573c04e70d9ec619a7cbed7f"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:3ddacd27458c45bdacd6bd6db644bfb730efbf9e830310186e3045c9c5be8fb2"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:588461c2e8384d309bd63e5826019b6977bc66d629b99ac8737bb795d7b2cb5a"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:e80e6c2f55656b4824d72065abb4ddd6a525c74bd78a0aab5d9fc2cf4fb5af50"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:d4a7319f304a774bed22115bc891618e45f85065ab44ea6acd07d274e750519a"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:fd1fbe0f116b6e55da77aca2c6ddcddcfac2186cbf78bdebf40fc156efca389d"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-win32.whl", hash = "sha256:93223adc95033dd47133a46ccfc316a0139176fd79085762e27202ec56018f03"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-win_amd64.whl", hash = "sha256:15bb4005af6320d259dc7593ca84a38d7fe06a421dbcf7b910ae23979101e787"}, + {file = "charset_normalizer-3.5.2-cp39-cp39-win_arm64.whl", hash = "sha256:2cc961b171b3f3440f410489ab3573e86aea8736134ebbb40ea1338b7f0831bc"}, + {file = "charset_normalizer-3.5.2-py3-none-any.whl", hash = "sha256:b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685"}, + {file = "charset_normalizer-3.5.2.tar.gz", hash = "sha256:39de2a259fc954455c57274dc94c79d5842774e1247a016aff30bc0efed0f4ef"}, ] -[package.dependencies] -colorama = {version = "*", markers = "platform_system == \"Windows\""} - [[package]] name = "colorama" version = "0.4.6" description = "Cross-platform colored terminal text." optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" -groups = ["main", "dev", "docs"] +groups = ["dev", "docs"] files = [ {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, ] -markers = {main = "platform_system == \"Windows\"", dev = "platform_system == \"Windows\" or sys_platform == \"win32\"", docs = "platform_system == \"Windows\" or sys_platform == \"win32\""} +markers = {dev = "platform_system == \"Windows\" or sys_platform == \"win32\"", docs = "sys_platform == \"win32\""} [[package]] name = "coverage" -version = "7.14.0" +version = "7.16.2" description = "Code coverage measurement for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "coverage-7.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:84c32d90bf4537f0e7b4dec9aaa9a938fb8205136b9d2ecf4d7629d5262dc075"}, - {file = "coverage-7.14.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:7c843572c605ab51cfdb5c6b5f2586e2a8467c0d28eca4bdef4ec70c5fecbd82"}, - {file = "coverage-7.14.0-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:0c451757d3fa2603354fdc789b5e58a0e327a117c370a40e3476ba4eabab228c"}, - {file = "coverage-7.14.0-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:3fd43f0616e765ab78d069cf8358def7363957a45cee446d65c502dcfeea7893"}, - {file = "coverage-7.14.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:731e535b1498b27d13594a0527a79b0510867b0ad891532be41cb883f2128e20"}, - {file = "coverage-7.14.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c7492f2d493b976941c7ca050f273cbda2f43c381124f7586a3e3c16d1804fec"}, - {file = "coverage-7.14.0-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:dc38367eaa2abb1b766ac333142bce7655335a73537f5c8b75aaa89c2b987757"}, - {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0a951308cde22cf77f953955a754d04dccb57fe3bb8e345d685778ed9fc1632a"}, - {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:fab3877e4ebb06bd9d4d4d00ee53309ee5478e66873c66a382272e3ee33eb7ea"}, - {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:b812eb847b19876ebf33fb6c4f11819af05ab6050b0bfa1bc53412ae81779adb"}, - {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d9c8ef6ed820c433de075657d72dda1f89a2984955e58b8a75feb3f184250218"}, - {file = "coverage-7.14.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d128b1bba9361fbaaf6a19e179e6cfd6a9103ce0c0555876f72780acc93efd85"}, - {file = "coverage-7.14.0-cp310-cp310-win32.whl", hash = "sha256:65f267ca1370726ec2c1aa38bbe4df9a71a740f22878d2d4bf59d71a4cd8d323"}, - {file = "coverage-7.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:b34ece8065914f938ed7f2c5872bb865336977a52919149846eac3744327267a"}, - {file = "coverage-7.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6a78e2a9d9c5e3b8d4ab9b9d28c985ea66fced0a7d7c2aec1f216e03a2011480"}, - {file = "coverage-7.14.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a1816c505187592dcd1c5a5f226601a549f70365fbd00930ac88b0c225b76bb4"}, - {file = "coverage-7.14.0-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:d8e1762f0e9cbc26ec315471e7b47855218e833cd5a032d706fbf43845d878c7"}, - {file = "coverage-7.14.0-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9336e23e8bb3a3925398261385e2a1533957d3e760e91070dcb0e98bfa514eed"}, - {file = "coverage-7.14.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9cd1169b2230f9cbe9c638ba38022ed7a2b1e641cc07f7cea0365e4be2a74980"}, - {file = "coverage-7.14.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d1bb3543b58fea74d2cd1abc4054cc927e4724687cb4560cd2ed88d2c7d820c0"}, - {file = "coverage-7.14.0-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:a93bac2cb577ef60074999ed56d8a1535894398e2ed920d4185c3ec0c8864742"}, - {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5904abf7e18cddc463219b17552229650c6b79e061d31a1059283051169cf7d5"}, - {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:741f57cddc9004a8c81b084660215f33a6b597dbe62c31386b983ee26310e327"}, - {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:664123feb0929d7affc135717dbd70d61d98688a08ab1e5ba464739620c6252d"}, - {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:c83d2399a51bbec8429266905d33616f04bc5726b1138c35844d5fcd896b2e20"}, - {file = "coverage-7.14.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb2e855b87321259a037429288ae85216d191c74de3e79bf57cd2bc0761992c"}, - {file = "coverage-7.14.0-cp311-cp311-win32.whl", hash = "sha256:731dc15b385ac52289743d476245b61e1a2927e803bef655b52bc3b2a75a21f3"}, - {file = "coverage-7.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:bfb0ed8ec5d25e93face268115d7964db9df8b9aae8edcde9ec6b16c726a7cc1"}, - {file = "coverage-7.14.0-cp311-cp311-win_arm64.whl", hash = "sha256:7ebb1c6df9f78046a1b1e0a89674cd4bf73b7c648914eebcf976a57fd99a5627"}, - {file = "coverage-7.14.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7ffd19fc8aed057fd686a17a4935eef5f9859d69208f96310e893e64b9b6ccf5"}, - {file = "coverage-7.14.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:829994cfe1aeb773ca27bf246d4badc1e764893e3bfb98fff820fcecd1ca4662"}, - {file = "coverage-7.14.0-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:b4f07cf7edcb7ec39431a5074d7ea83b29a9f71fcfc494f0f40af4e65180420f"}, - {file = "coverage-7.14.0-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:ca3d9cf2c32b521bd9518385608787fa86f38daf993695307531822c3430ed67"}, - {file = "coverage-7.14.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:92af52828e7f29d827346b0294e5a0853fa206db77db0395b282918d41e28db9"}, - {file = "coverage-7.14.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:7b2bb6c9d7e769360d0f20a0f219603fd64f0c8f97de17ab25853261602be0fb"}, - {file = "coverage-7.14.0-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1c9ed6ef99f88fb8c14aa8e2bf8eb0fe55fa2edfea68f8675d78741df1a5ac0e"}, - {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:8231ade007f37959fbf58acc677f26b922c02eda6f0428ea307da0fd39681bf3"}, - {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:d8b013632cc1ce1d09dbe4f32667b4d320ec2f54fc326ebeffcd0b0bcc2bb6c4"}, - {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:1733198802d71ec4c524f322e2867ee05c62e9e75df86bdca545407a221827d1"}, - {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:72a305291fa8ee01332f1aaf38b348ca34097f6aa0b0ef627eef2837e57bbba5"}, - {file = "coverage-7.14.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fcaba850dd317c65423a9d63d88f9573c53b00354d6dd95724576cc98a131595"}, - {file = "coverage-7.14.0-cp312-cp312-win32.whl", hash = "sha256:5ac83957a80d0701310e96d8bec68cdcf4f90a7674b7d13f15a344315b41ab27"}, - {file = "coverage-7.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:70390b0da32cb90b501953716302906e8bcce087cb283e70d8c97729f22e92b2"}, - {file = "coverage-7.14.0-cp312-cp312-win_arm64.whl", hash = "sha256:91b993743d959b8be85b4abf9d5478216a69329c321efe5be0433c1a841d691d"}, - {file = "coverage-7.14.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f2bbb8254370eb4c628ff3d6fa8a7f74ddc40565394d4f7ab791d1fe568e37ef"}, - {file = "coverage-7.14.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:23b81107f46d3f21d0cbce30664fcec0f5d9f585638a67081750f99738f6bf66"}, - {file = "coverage-7.14.0-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:22a7e06a5f11a757cdfe79018e9095f9f69ae283c5cd8123774c788deec8717b"}, - {file = "coverage-7.14.0-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9d1aa57a1dc8e05bdc42e81c5d671d849577aeedf279f4c449d6d286f9ed88ca"}, - {file = "coverage-7.14.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:90c1a51bcfddf645b3bb7ec333d9e94393a8e94f55642380fa8a9a5a9e636cb7"}, - {file = "coverage-7.14.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a841fae2fadcae4f438d43b6ccc4aac2ad609f47cdb6cfdce60cbb3fe5ca7bc2"}, - {file = "coverage-7.14.0-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c79d2319cabef1fe8e86df73371126931550804738f78ad7d31e3aad85a67367"}, - {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1b23b0c6f0b1db6ad769b7050c8b641c0bf215ded26c1816955b17b7f26edfa9"}, - {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:55d3089079ce181a4566b1065ab28d2575eb76d8ac8f81f4fcda2bf037fee087"}, - {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:49c005cba1e2f9677fb2845dcdf9a2e72a52a17d63e8231aaaae35d9f50215ef"}, - {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:9117377b823daa28aa8635fbb08cda1cd6be3d7143257345459559aeef852d52"}, - {file = "coverage-7.14.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:7b79d646cf46d5cf9a9f40281d4441df5849e445726e369006d2b117710b33fe"}, - {file = "coverage-7.14.0-cp313-cp313-win32.whl", hash = "sha256:fb609b3658479e33f9516d46f1a89dbb9b6c261366e3a11844a96ec487533dae"}, - {file = "coverage-7.14.0-cp313-cp313-win_amd64.whl", hash = "sha256:0773d8329cf32b6fd222e4b52622c61fe8d503eb966cfc8d3c3c10c96266d50e"}, - {file = "coverage-7.14.0-cp313-cp313-win_arm64.whl", hash = "sha256:b4e26a0f1b696faf283bffe5b8569e44e336c582439df5d53281ab89ee0cba96"}, - {file = "coverage-7.14.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:953f521ca9445300397e65fda3dca58b2dbd68fee983777420b57ac3c77e9f90"}, - {file = "coverage-7.14.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:98af83fd65ae24b1fdd03aaead967a9f523bcd2f1aab2d4f3ffda65bb568a6f1"}, - {file = "coverage-7.14.0-cp313-cp313t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:668b92e6958c4db7cf92e81caac328dfbbdbb215db2850ad28f0cbe1eea0bfbd"}, - {file = "coverage-7.14.0-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:9fbd898551762dea00d3fef2b1c4f99afd2c6a3ff952ea07d60a9bd5ed4f34bc"}, - {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:68af363c07ecd8d4b7d4043d85cb376d7d227eceb54e5323ee45da73dbd3e426"}, - {file = "coverage-7.14.0-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:6e57054a583da8ac55edf24117ea4c9133032cfc4cf72aa2d48c1e5d4b52f899"}, - {file = "coverage-7.14.0-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cc3499459bbcdd51a65b64c35ab7ed2764eaf3cba826e0df3f1d7fe2e102b70b"}, - {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:45899ec2138a4346ed34d601dedf5076fb74edf2d1dd9dc76a78e82397edee90"}, - {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:8767486808c436f05b23ab98eb963fb29185e32a9357a166971685cb3459900f"}, - {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a3b5ddfd6aa7ddad53ee3edb231e88a2151507a43229b7d71b953916deca127d"}, - {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:63df0fe568e698e1045792399f8ab6da3a6c2dce3182813fb92afa2641087b47"}, - {file = "coverage-7.14.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:827d6397dbd95144939b18f89edf31f63e1f99633e8d5f32f22ba8bdda567477"}, - {file = "coverage-7.14.0-cp313-cp313t-win32.whl", hash = "sha256:7bf43e000d24012599b879791cff41589af90674722421ef11b11a5431920bab"}, - {file = "coverage-7.14.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3f5549365af25d770e06b1f8f5682d9a5637d06eb494db91c6fa75d3950cc917"}, - {file = "coverage-7.14.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6d160217ec6fe890f16ad3a9531761589443749e448f91986c972714fad361c8"}, - {file = "coverage-7.14.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:9aed9fa983514ca032790f3fe0d1c0e42ca7e16b42432af1706b50a9a46bef5d"}, - {file = "coverage-7.14.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ba3b8390db29296dbbf49e91b6fe08f990743a90c8f447ba4c2ffc29670dfa63"}, - {file = "coverage-7.14.0-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:3a5d8e876dfa2f102e970b183863d6dedd023d3c0eeca1fe7a9787bc5f28b212"}, - {file = "coverage-7.14.0-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5ebb8f4614a3787d567e610bbfdf96a4798dd69a1afb1bd8ad228d4111fe6ff3"}, - {file = "coverage-7.14.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b9bf47223dd8db3d4c4b2e443b02bace480d428f0822c3f991600448a176c97"}, - {file = "coverage-7.14.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:3485a836550b303d006d57cc06e3d5afaabc642c77050b7c985a97b13e3776b8"}, - {file = "coverage-7.14.0-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3e7e88110bae996d199d1693ca8ec3fd52441d426401ae963437598667b4c5eb"}, - {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:15228a6800ce7bdf1b74800595e56db7138cecb338fdbf044806e10dcf182dfe"}, - {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:9d26ac7f5398bafc5b57421ad994e8a4749e8a7a0e62d05ec7d53014d5963bfa"}, - {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:2fb73254ff43c911c967a899e1359bc5049b4b115d6e8fbdde4937d0a2246cd5"}, - {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:454a380af72c6adada298ed270d38c7a391288198dbfb8467f786f588751a90c"}, - {file = "coverage-7.14.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:65c86fb646d2bd2972e96bd1a8b45817ed907cee68655d6295fe7ec031d04cca"}, - {file = "coverage-7.14.0-cp314-cp314-win32.whl", hash = "sha256:6a6516b02a6101398e19a3f44820f69bab2590697f7def4331f668b14adaf828"}, - {file = "coverage-7.14.0-cp314-cp314-win_amd64.whl", hash = "sha256:45e0f79d8351fa76e256716df91eab12890d32678b9590df7ae1042e4bd4cf5d"}, - {file = "coverage-7.14.0-cp314-cp314-win_arm64.whl", hash = "sha256:4b899594a8b2d81e5cc064a0d7f9cac2081fed91049456cae7676787e41549c9"}, - {file = "coverage-7.14.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:f580f8c80acd94ac72e863efe2cab791d8c38d153e0b463b92dfa000d5c84cd1"}, - {file = "coverage-7.14.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a2bd259c442cd43c49b30fbafc51776eb19ea396faf159d26a83e6a0a5f13b0c"}, - {file = "coverage-7.14.0-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a706b908dfa85538863504c624b237a3cc34232bf403c057414ebfdb3b4d9f84"}, - {file = "coverage-7.14.0-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:7333cd944ee4393b9b3d3c1b598c936d4fc8d70573a4c7dacfec5590dd50e436"}, - {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f162bc9a15b82d947b02651b0c7e1609d6f7a8735ca330cfadec8481dd97d5a"}, - {file = "coverage-7.14.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:362cb78e01a5dc82009d88004cf60f2e6b6d6fcbfdec05b05af73b0abf40118f"}, - {file = "coverage-7.14.0-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:acebd068fca5512c3a6fde9c045f901613478781a73f0e82b307b214daef23fb"}, - {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:29fe3da551dface75deb2ccbf87b6b66e2e7ef38f6d89050b428be94afff3490"}, - {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:b4cc4fce8672fffcb09b0eafc167b396b3ba53c4a7230f54b7aaffbf6c835fa9"}, - {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:5d4a51aad8ba8bdcd2b8bd8f03d4aca19693fa2327a3470e4718a25b03481020"}, - {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:9f323af3e1e4f68b60b7b247e37b8515563a61375518fa59de1af48ba28a3db6"}, - {file = "coverage-7.14.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:1a0abc7342ea9711c469dd8b821c6c311e6bc6aac1442e5fbd6b27fae0a8f3db"}, - {file = "coverage-7.14.0-cp314-cp314t-win32.whl", hash = "sha256:a9f864ef57b7172e2db87a096642dd51e179e085ab6b2c371c29e885f65c8fb2"}, - {file = "coverage-7.14.0-cp314-cp314t-win_amd64.whl", hash = "sha256:29943e552fdc08e082eb51400fb2f58e118a83b5542bd06531214e084399b644"}, - {file = "coverage-7.14.0-cp314-cp314t-win_arm64.whl", hash = "sha256:742a73ea621953b012f2c4c2219b512180dd84489acf5b1596b0aafc55b9100b"}, - {file = "coverage-7.14.0-py3-none-any.whl", hash = "sha256:8de5b61163aee3d05c8a2beab6f47913df7981dad1baf82c414d99158c286ab1"}, - {file = "coverage-7.14.0.tar.gz", hash = "sha256:057a6af2f160a85384cde4ab36f0d2777bae1057bae255f95413cdd382aa5c74"}, + {file = "coverage-7.16.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:23219888477edd736b6fcaec1272d47d93b926e999641ffea7e53a1738e70b2b"}, + {file = "coverage-7.16.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:40c0f00899fe6181ae7f434ceb200e51f5ee4b8ed10e3b5f0b605f0cae15da87"}, + {file = "coverage-7.16.2-cp310-cp310-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:a4624f80732f6b427ac58f1f59c577a0994a12e8174b5af6a027b4b58795d4c3"}, + {file = "coverage-7.16.2-cp310-cp310-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:191803c4996b499fcd78c2ad5e5f767dcc53cb4dc6de6d6a741b443a1821ef02"}, + {file = "coverage-7.16.2-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9fd670ac43b709c575aefc25bf52d8a598a3bc5017bddfd0a179152ab06a2deb"}, + {file = "coverage-7.16.2-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:705e5af11d34647efdc170c7840b6857c81cf74be96419a553f237e68e62cb72"}, + {file = "coverage-7.16.2-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8afd9bf35cc6a1f22eb3634808fa8e0b91902459c5721ef2e4461dfe771d7f08"}, + {file = "coverage-7.16.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3f43bac1856ba269b905302778d4df433d6006489a192174ad77ac528e395032"}, + {file = "coverage-7.16.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:f8475460aa33ee28ac896ab1156d0bb3b6c639f7f8383c2677d3359eb35f8205"}, + {file = "coverage-7.16.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:d6276d78f6fca7d0ac066d5da4165c5acd07829e8305c2cb900b738fb3a75a72"}, + {file = "coverage-7.16.2-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:736fde09ea39646d11f8e3b76bd3425c075aa4dd45f24891970bb77c14ff20f5"}, + {file = "coverage-7.16.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:c85d54e7e8a2ca932fe8399301af9b8d5907ea2a455ffaff6e7d1208db83b943"}, + {file = "coverage-7.16.2-cp310-cp310-win32.whl", hash = "sha256:5139009b5efd2194fc168ee9362f0e191ba612ef5d29242f9269c22f9b8f80c7"}, + {file = "coverage-7.16.2-cp310-cp310-win_amd64.whl", hash = "sha256:c3305c38a2fa21a4254f2ace7dd9ef5fc569c9a558b66e7017650b3d637fb95e"}, + {file = "coverage-7.16.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:732d950e51f3ba4fb6209c73250f3e8924fefca42953ee04a9e65d8c02414d7d"}, + {file = "coverage-7.16.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:5dca0bb66b4c3d624ba047887bf70270030c150692d543cb501293dc38a9f4b5"}, + {file = "coverage-7.16.2-cp311-cp311-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:af2a2a8c7c74de0559e0c368d94c8def9e16c58faaee33a0bf081057c4227e3b"}, + {file = "coverage-7.16.2-cp311-cp311-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:db5f8394e17f877a625b257f2ba0ce8e728a499c2c1579ad66220272cd3df510"}, + {file = "coverage-7.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5b3146d2317c75f70df2509066d979dadd941f7021cdf9b5db4bcd8568258e25"}, + {file = "coverage-7.16.2-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9e1d0ced76318bab499693ff25f64faa343415187cb2e4d7befdfdd391a1cf6a"}, + {file = "coverage-7.16.2-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:af98ad5ed9d6daaca956201e00bb429a7eb2b080426686f70a20353e0f9839f5"}, + {file = "coverage-7.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1d56e4d21c56d2046447733f8b118409597db48c01efe898ee9ac24e858ec2d6"}, + {file = "coverage-7.16.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:1d5d0e3b660506fb84f995814e3118a21efdc0c8eb80127da1be627d90093c17"}, + {file = "coverage-7.16.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:17228fbca0f22976f797be94e975dcd237799c657d49551c7de1e0654d1202e9"}, + {file = "coverage-7.16.2-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:bc0b0ac781d489304b741269857f1f8338b7a26b1b89c06c0344658001ec0035"}, + {file = "coverage-7.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bf1bd822ec4e387ed245bed0d71151582cf7be9e5309bc4145eefe36083d5878"}, + {file = "coverage-7.16.2-cp311-cp311-win32.whl", hash = "sha256:7ed238d227e23cc300c3d464babdaf9f6ddc740aa1b15a77ae96136e6a7c4516"}, + {file = "coverage-7.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:a90700f743e29aa3d75a6ff5f01953176a889c00e526194bc4d281731b88d99d"}, + {file = "coverage-7.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:a336eec40e3520d369b8a6cdabb4f596e69a8b42927ca074aa1452fed943238a"}, + {file = "coverage-7.16.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:218d742afca2b5ad5ca759e93eddedfbcc6eadf8322f080dcefc40b7bd4e2d48"}, + {file = "coverage-7.16.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a9a638be322a8d76a41cdb17781c7f82aaee6a66493d8ffb7e2c09ee22423d99"}, + {file = "coverage-7.16.2-cp312-cp312-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:724bd0f1e81856b35e59fc98cf7b4e544a3cb662e4e0864dca73d4326ee9d808"}, + {file = "coverage-7.16.2-cp312-cp312-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:5375ebd99038021b35e99dc88255022912c06565d316212f4a576e4b08d30f5d"}, + {file = "coverage-7.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a076277ca9f5750cc230f0f578ebd2620cec60255b25707361699fef6fb465c"}, + {file = "coverage-7.16.2-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:58d4a54c6ea672afef66d49be922a2c69826c5ae1a42a9cd94f0c9c2bacdf800"}, + {file = "coverage-7.16.2-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0dcbcfcc059117284c603ff8cb61a65872512882f84a8cf0339241f7f7c2f148"}, + {file = "coverage-7.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:afdf43b72ef3876c1fe66423b91466e37877c9e81e8cec70542b7e8525b9d1b7"}, + {file = "coverage-7.16.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:9acc7f7ec4a1b5f89bd929fde5b8a714f6fafdc6cc18725413d510aa082b47ad"}, + {file = "coverage-7.16.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:80d3f7b48d43ee8fc5e8707a8adb43d743a5a1a85256c25a24f9d6d0e2238fa6"}, + {file = "coverage-7.16.2-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:126d1af8804d7224421fe991ff65d3ce649081560df7a98b1a5ffff07f9923bd"}, + {file = "coverage-7.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c19cd6d025c1673f22afcd22c7df8a662d779e05d8e3fa6820c22afb895b0206"}, + {file = "coverage-7.16.2-cp312-cp312-win32.whl", hash = "sha256:152877cdc8a07264882cfcd503ba56a3ef6cba56a70e8c70f6eb8ffd7384789a"}, + {file = "coverage-7.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:e6c52d3307824ff93b39efd99e4185d557db40bd841452abfb32e5d9151ca162"}, + {file = "coverage-7.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:a678c0b6b22086ec2427359d22e37445d4a792f5fdbbc744112c7dade65cad02"}, + {file = "coverage-7.16.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:1a37c6e478cf687e1aa30a593d19c92c02fad9d122b51ab73f51b8dc7a0c0fc9"}, + {file = "coverage-7.16.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0993d0e90858c03943d3cb152e068a20dd4707924deec84dd2230261baae3b1b"}, + {file = "coverage-7.16.2-cp313-cp313-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:bb2fc905bbf4e6b7f40806ea79e31515abf6349594cdf0adf27c4215f0463204"}, + {file = "coverage-7.16.2-cp313-cp313-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:4358b9c8c0125b460407f3017c6cce8156e904b32772c5630d27112f52bdbfe5"}, + {file = "coverage-7.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1f15254427c9b33eedac4f198eaf9e356eb4f6214551afb43da6194a2c088ad7"}, + {file = "coverage-7.16.2-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9a75a4704ff640e46170042eec1f984385a121227c505d5a16ad8e495f452541"}, + {file = "coverage-7.16.2-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:14253fc7bb15749b849795a06f5d3b6d8bc3fb8a4b5ddc341faf7a89dce205fc"}, + {file = "coverage-7.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:921415102a90637fcc2e3f169f61dad7699ecf690e8639fc21b813acbedc0967"}, + {file = "coverage-7.16.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cce2bc991293f15cc4084ca116827b5900c5f34e1a54dfe83f10ab5c43162eb7"}, + {file = "coverage-7.16.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:e1fa594c887365b69745f25a416806e61085dd07b94c9eae68a6e20730629b23"}, + {file = "coverage-7.16.2-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:11e597173af1dc33d5f8a7332ada544199269a223af1ee1770ddd5e245ad0fe8"}, + {file = "coverage-7.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e7f99698ba3a7d13988bdd984b7ebf13af4dbe2166dc8502eef90d77603b0a4"}, + {file = "coverage-7.16.2-cp313-cp313-win32.whl", hash = "sha256:f80bd9f9633eafc73d0a913ba2645c96ba58bba1befc30590f7c0fbfde59d865"}, + {file = "coverage-7.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:8be099e979fc42559328a21828281b4578304191ae46ed4e80a407048a82eee6"}, + {file = "coverage-7.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:28ff850182a67d117990fa2ce5ea1032836d8c9630dae867e8bdd3bff4533b79"}, + {file = "coverage-7.16.2-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4ee546b9e4872ffa194bf07ac87bfa1202ebb824d0795dc1ef22f175545ca90a"}, + {file = "coverage-7.16.2-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:a2fac6895eb299a2e52d7bbb8fb3903502b9da8d3f5309ceb16ec40c646b58ee"}, + {file = "coverage-7.16.2-cp314-cp314-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:57ff3783f99d75a1e81dd56a9737eb5665e6736a5d93258ba596b6dcad8fd05b"}, + {file = "coverage-7.16.2-cp314-cp314-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:35f37886699cb9abd29958247d718628d5bc6f39e623dff66a09e546c42a7e03"}, + {file = "coverage-7.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0fd7a86fdda7cb6d616d178654bd0ad6bc0f3f33c2e478aa598500a1a9e34eda"}, + {file = "coverage-7.16.2-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ac0f3b379c94acc2f7dce5f5f0b24d44fa1cc6a509717ef83dfee07450c2117c"}, + {file = "coverage-7.16.2-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7d0732c83746bc24123c581a85d9dd96b70ddb538c9076020aa1a041790361e9"}, + {file = "coverage-7.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:7b451c68218c150f616bc9649783ec8de76a59792c759b43aa0c9c0466a465e4"}, + {file = "coverage-7.16.2-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a56ac4fa5a75c7e182e8f62600cfb4aff43c5ed7356a034f3557659c3bec1d90"}, + {file = "coverage-7.16.2-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:4cc4f73aa3fabc36e32046d6cd2971405948d8a903636508a3d3b2f9128b3a95"}, + {file = "coverage-7.16.2-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:723dcdab91357159b722935b500ee8abc0a66c8c432e1e9fabf4cc7598952de8"}, + {file = "coverage-7.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5397e21a90dde0e9c6896b77ded8f0be26b66f8b22b33aed41f6043ed95d55e6"}, + {file = "coverage-7.16.2-cp314-cp314-win32.whl", hash = "sha256:848893e1d361448c113dc2f0913503522a6f7be231d0e38333d2a22d9698a011"}, + {file = "coverage-7.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:5a27b731c171e43dc8b5f32b76a5051dde2ec9b9366c87028f08a7088ebc2c7b"}, + {file = "coverage-7.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:1c569a9fd25505f1cd6bea90588818f90373ce90e2632e2cacf19ddbd6e14fdb"}, + {file = "coverage-7.16.2-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:d93db87adb6b1c1b408dce4763314b55d76a9f589e96783a84ac9e7689e48bdf"}, + {file = "coverage-7.16.2-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:aa62c85046473959c13ba9edca9dc90a77d5c1095b1ba313556314d77fe5b036"}, + {file = "coverage-7.16.2-cp314-cp314t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:db76506aa5416081f3e8974ae0f7965c58ada0bb0ef7339ac86099588dbb20d3"}, + {file = "coverage-7.16.2-cp314-cp314t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:a0f2285329dac10ab08f79cb11f5692c497018e6c7c511f95e6fd63a70b8f831"}, + {file = "coverage-7.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:382d3346d56b0eec1b793d53a4c88799c8053f516aa3a8d7c44315696954bacf"}, + {file = "coverage-7.16.2-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:648352b94507179d82637292e7ae8802508d95f78e2f00a705a50b6c48011681"}, + {file = "coverage-7.16.2-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:fb2bde05838fffae1a1bf75e5d411a6cac3e4e9bb97e6640fed8cd47888b33f0"}, + {file = "coverage-7.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:6a75180829efb8ae62b4aded25be6ddca1c888d138d2d82e21d93bfbd88f41cb"}, + {file = "coverage-7.16.2-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:99704f73721e23859112072d522076e11c31744fc96b5652e5dd2018aa4359f7"}, + {file = "coverage-7.16.2-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:29309ccc86b7f33df7db12813c299f215bbbc470ed6292d0bedd63ffae1ebf64"}, + {file = "coverage-7.16.2-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:30c1b65d529e46569899fadca59e4a87c1faf2886923f1307ba61e654d4f3c20"}, + {file = "coverage-7.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dcf4bc2aab4e16b1c4c0c2005918f23a7dd5d7821ddae82caed9e3342dc2fcce"}, + {file = "coverage-7.16.2-cp314-cp314t-win32.whl", hash = "sha256:a9cd3de0a5bfe7b0e21ee10e1a14e3d61bf52efc88217ab1d95d6ace6970bd46"}, + {file = "coverage-7.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:611a44e5229a59d7483ce830160e1a0e85f700562c7a5651c7c63fb8f4eb528c"}, + {file = "coverage-7.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:22957cef43ce038641de78ba995de7568d2d6a37c6ddbf7fa0fd7d1ae2344d91"}, + {file = "coverage-7.16.2-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:414c26dfdb96aac2d570a54e03008f001e32eb2d413705365503648c6bd361d8"}, + {file = "coverage-7.16.2-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:00d3eb96e9988c45f50cccd1f1496571ac5c1f91386ac02c4d55516eeda19a24"}, + {file = "coverage-7.16.2-cp315-cp315-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:4dbbd1155ca46e6e0b6b89d204428c56ef6a459af21333f365d135a2820e5a09"}, + {file = "coverage-7.16.2-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:8fc15cc8d0d06e873c00ef18e1372d605f9aaf3de27d8c24e50782e75bc8b843"}, + {file = "coverage-7.16.2-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:9c6afdd69218202bc1758c9a14b86b8cf1084f37ed2ca143e567a103772b16d1"}, + {file = "coverage-7.16.2-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:aba5c63b7afdc749cc9eae943d5b868cba2b261a176378fa1c5a30bc8bc89982"}, + {file = "coverage-7.16.2-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9174f0af24e5eff248b9dbfe76ec5275a3d19d37edbc2810543f12cf97347a34"}, + {file = "coverage-7.16.2-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:80e9fdb4c3d926b6ba721d4bf7435bdb869c3527ae7803290361d0ab73db13b6"}, + {file = "coverage-7.16.2-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:7b3bce4a0d05401d70b7d0d5ca783e686bc9d30e81dbd7d980d532609bf809e4"}, + {file = "coverage-7.16.2-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:44f21e407b278efdfc1ee5e481e00518bd1d500310a30a5fbf2bcbedfef4aaf0"}, + {file = "coverage-7.16.2-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:59c3926585e1cd1f2190f4b2ac9014de1bbeaf0d5d0587b0dc6b0aa90d17896a"}, + {file = "coverage-7.16.2-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:066429634299e14dd2d511e1e85f8f9cecc500781f6b41907c0dd6f1baea7e63"}, + {file = "coverage-7.16.2-cp315-cp315-win32.whl", hash = "sha256:893ea9cf86cb8d2546812ac93d973aaf2ee1fb45110a873b014214fd23e3725e"}, + {file = "coverage-7.16.2-cp315-cp315-win_amd64.whl", hash = "sha256:01c6908bc613b420c26c818fe948e1b97dfd041a53c98b01c63bd8321f5c9aae"}, + {file = "coverage-7.16.2-cp315-cp315-win_arm64.whl", hash = "sha256:967d72c835d7a8cf0af99ec813a2d06e3db6df706402f1fe85b31b437645f495"}, + {file = "coverage-7.16.2-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:98d9c97f51b334b0adce7b964442a9af33c1a00c6ac856984cc5dc8d18f81c75"}, + {file = "coverage-7.16.2-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:3e861f1071dcc2fec1e88bef0920f6b1eaa66a143555b4f8ab79ba2b0f30ef55"}, + {file = "coverage-7.16.2-cp315-cp315t-manylinux1_i686.manylinux_2_28_i686.manylinux_2_5_i686.whl", hash = "sha256:fb9d92ecfe2d5b494367c67f7446f8b75b68d8d0c8cf3bc3e6997478be25d9e2"}, + {file = "coverage-7.16.2-cp315-cp315t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:eb57acff4a74246ae513c142d4b36e18c389c3aed8661914a53f7cd0071031b2"}, + {file = "coverage-7.16.2-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:444889f7f66b74e4455c0a97e0e166dd41177f1dca8c0239a47cff25e05ba7e1"}, + {file = "coverage-7.16.2-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:a740ea6f083c6db7b926534d159508f80ba275ab35e722522de0d18d0f56e55f"}, + {file = "coverage-7.16.2-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8e209591f7c41ae4a9171335cf6156afda0b21de73b02f73f5aa95b2d5fbb08d"}, + {file = "coverage-7.16.2-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:396bb16e04ce04efbb3df91456ae4e3da918e69ecdf67fb711b0a0fdf35ccce0"}, + {file = "coverage-7.16.2-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:9cdf19874e0d247f32f03609200370343c3c7aa260b191d8c2bb251d36198283"}, + {file = "coverage-7.16.2-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:fd3d72233eb8b48acc94fa57d44e2d32ce8e7abed02882ccb6d855ccc4ed33ec"}, + {file = "coverage-7.16.2-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:bb4ffe96aa663cee727659db5a2afeb38c95f8677b747d447b90d6d4874ea2c5"}, + {file = "coverage-7.16.2-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:dba2edfb054f6d4a08df9d1637c39a5aa3865bca6617c13c86be21e45658a59c"}, + {file = "coverage-7.16.2-cp315-cp315t-win32.whl", hash = "sha256:251aed777c47c77aba047096d4542889db089227655711dfc2b9c54ef0e15e35"}, + {file = "coverage-7.16.2-cp315-cp315t-win_amd64.whl", hash = "sha256:2aca0bdfa9e91621d5b09d815357bf63def4fc0e9cb66da67bf2cf93f3b1a6f5"}, + {file = "coverage-7.16.2-cp315-cp315t-win_arm64.whl", hash = "sha256:b88841e654f09732804809e435b3e005a929ffd9998b872b7b213957b8759cb8"}, + {file = "coverage-7.16.2-py3-none-any.whl", hash = "sha256:11d28e9123a9156cb405d8d27b44256c9a58fb5decc2073a8f17862057e3aa0f"}, + {file = "coverage-7.16.2.tar.gz", hash = "sha256:ca64d9f1f384f151b9511bec01126072acd2f313439f8ed015a22d8790aab6fa"}, ] [package.extras] @@ -1096,14 +1186,14 @@ ssh = ["bcrypt (>=3.1.5)"] [[package]] name = "distlib" -version = "0.4.0" +version = "0.4.3" description = "Distribution utilities" optional = false python-versions = "*" groups = ["dev"] files = [ - {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, - {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, + {file = "distlib-0.4.3-py2.py3-none-any.whl", hash = "sha256:4b0ce306c966eb73bc3a7b6abad017c556dadd92c44701562cd528ac7fde4d5b"}, + {file = "distlib-0.4.3.tar.gz", hash = "sha256:f152097224a0ae24be5a0f6bae1b9359af82133bce63f98a95f86cae1aede9ed"}, ] [[package]] @@ -1120,26 +1210,26 @@ files = [ [[package]] name = "filelock" -version = "3.29.0" +version = "4.0.11" description = "A platform independent file lock." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "filelock-3.29.0-py3-none-any.whl", hash = "sha256:96f5f6344709aa1572bbf631c640e4ebeeb519e08da902c39a001882f30ac258"}, - {file = "filelock-3.29.0.tar.gz", hash = "sha256:69974355e960702e789734cb4871f884ea6fe50bd8404051a3530bc07809cf90"}, + {file = "filelock-4.0.11-py3-none-any.whl", hash = "sha256:1cbdc4ace7fb11d2f6d073f5c3d91537a23b3d58d2bf2fdffc12c6d717a589c6"}, + {file = "filelock-4.0.11.tar.gz", hash = "sha256:9dc453a1edd25626a6fc97c2cb1bd9f7e46345843d40b3181c071761fb9a5f7a"}, ] [[package]] name = "identify" -version = "2.6.19" +version = "2.6.20" description = "File identification library for Python" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "identify-2.6.19-py2.py3-none-any.whl", hash = "sha256:20e6a87f786f768c092a721ad107fc9df0eb89347be9396cadf3f4abbd1fb78a"}, - {file = "identify-2.6.19.tar.gz", hash = "sha256:6be5020c38fcb07da56c53733538a3081ea5aa70d36a156f83044bfbf9173842"}, + {file = "identify-2.6.20-py2.py3-none-any.whl", hash = "sha256:6a16b69b93187244e0548cbfd25b3e4a6f9a7a2ad784625c3bec2b8d27b81aaa"}, + {file = "identify-2.6.20.tar.gz", hash = "sha256:ad729860a923858d26917c2f4fb0a1d83d27a75b1e090c06440c573f048f3285"}, ] [package.extras] @@ -1147,29 +1237,29 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.15" +version = "3.20" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["main", "dev", "docs"] files = [ - {file = "idna-3.15-py3-none-any.whl", hash = "sha256:048adeaf8c2d788c40fee287673ccaa74c24ffd8dcf09ffa555a2fbb59f10ac8"}, - {file = "idna-3.15.tar.gz", hash = "sha256:ca962446ea538f7092a95e057da437618e886f4d349216d2b1e294abfdb65fdc"}, + {file = "idna-3.20-py3-none-any.whl", hash = "sha256:ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c"}, + {file = "idna-3.20.tar.gz", hash = "sha256:a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44"}, ] [package.extras] -all = ["mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] +all = ["coverage (>=7.10.0)", "hypothesis (>=6.141.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.16.0)", "ty (>=0.0.37)"] [[package]] name = "imagesize" -version = "1.5.0" -description = "Getting image size from png/jpeg/jpeg2000/gif file" +version = "2.0.1" +description = "Get image size from headers (BMP/PNG/JPEG/JPEG2000/GIF/TIFF/SVG/Netpbm/WebP/AVIF/HEIC/HEIF)" optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +python-versions = ">=3.10" groups = ["docs"] files = [ - {file = "imagesize-1.5.0-py2.py3-none-any.whl", hash = "sha256:32677681b3f434c2cb496f00e89c5a291247b35b1f527589909e008057da5899"}, - {file = "imagesize-1.5.0.tar.gz", hash = "sha256:8bfc5363a7f2133a89f0098451e0bcb1cd71aba4dc02bbcecb39d99d40e1b94f"}, + {file = "imagesize-2.0.1-py3-none-any.whl", hash = "sha256:ea0c9a0384df69ed86a943a15cde37d0360b82491b3910dc2215e202e62b5b02"}, + {file = "imagesize-2.0.1.tar.gz", hash = "sha256:b2ba6a4dea487a7ebcd53248d3476aca449d30db12a2dde5e0c5ca9624fd77e5"}, ] [[package]] @@ -1243,7 +1333,7 @@ files = [ [package.dependencies] attrs = ">=22.2.0" -jsonschema-specifications = ">=2023.3.6" +jsonschema-specifications = ">=2023.03.6" referencing = ">=0.28.4" rpds-py = ">=0.25.0" @@ -1268,103 +1358,150 @@ referencing = ">=0.31.0" [[package]] name = "librt" -version = "0.11.0" +version = "0.16.0" description = "Mypyc runtime library" optional = false python-versions = ">=3.9" groups = ["dev"] markers = "platform_python_implementation != \"PyPy\"" files = [ - {file = "librt-0.11.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6e94ebfcfa2d5e9926d6c3b9aa4617ffc42a845b4321fb84021b872358c82a0f"}, - {file = "librt-0.11.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:ae627397a2f351560440d872d6f7c8dbb4072e57868e7b2fc5b8b430fe489d45"}, - {file = "librt-0.11.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc329359321b67d24efdf4bc69012b0597001649544db662c001db5a0184794c"}, - {file = "librt-0.11.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:7e82e642ab0f7608ce2fe53d76ca2280a9ee33a1b06556142c7c6fe80a86fc33"}, - {file = "librt-0.11.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:88145c15c67731d54283d135b03244028c750cc9edc334a96a4f5950ebdb2884"}, - {file = "librt-0.11.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9d36a51b3d93320b686588e27123f4995804dbf1bce81df78c02fc3c6eea9280"}, - {file = "librt-0.11.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:d00f3ac06a2a8b246327f11e186a53a100a4d5c7ed52346367e5ec751d51586c"}, - {file = "librt-0.11.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:461bbceede621f1ffb8839755f8663e886087ee7af16294cab7fb4d782c62eeb"}, - {file = "librt-0.11.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:0cad8a4d6a8ff03c9b76f9414caccd78e7cfbc8a2e12fa334d8e1d9932753783"}, - {file = "librt-0.11.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:f37aa505b3cf60701562eddb32df74b12a9e380c207fd8b06dd157a943ac7ea0"}, - {file = "librt-0.11.0-cp310-cp310-win32.whl", hash = "sha256:94663a21534637f0e787ec2a2a756022df6e5b7b2335a5cdd7d8e33d68a2af89"}, - {file = "librt-0.11.0-cp310-cp310-win_amd64.whl", hash = "sha256:dec7db73758c2b54953fd8b7fe348c45188fe26b39ee18446196edd08453a5d4"}, - {file = "librt-0.11.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:93d95bd45b7d58343d8b90d904450a545144eec19a002511163426f8ab1fae29"}, - {file = "librt-0.11.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4ee278c769a713638cdacd4c0436d72156e75df3ebc0166ab2b9dc43acc386c9"}, - {file = "librt-0.11.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f230cb1cbc9faaa616f9a678f530ebcf186e414b6bcbd88b960e4ba1b92428d5"}, - {file = "librt-0.11.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5d63c855d86938d9de93e265c9bd8c705b51ec494de5738340ee93767a686e4b"}, - {file = "librt-0.11.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:993f028be9e96a08d31df3479ac80d99be374d17f3b78e4796b3fd3c913d4e89"}, - {file = "librt-0.11.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:258d73a0aa66a055e65b2e4d1b8cdb23b9d132c5bb915d9547d804fcaed116cc"}, - {file = "librt-0.11.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:0827efe7854718f04aaddf6496e96960a956e676fe1d0f04eb41511fd8ad06d5"}, - {file = "librt-0.11.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:7753e57d6e12d019c0d8786f1c09c709f4c3fcc57c3887b24e36e6c06ec938b7"}, - {file = "librt-0.11.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:11bd19822431cc21af9f27374e7ae2e58103c7d98bda823536a6c47f6bb2bb3d"}, - {file = "librt-0.11.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:22bdf239b219d3993761a148ffa134b19e52e9989c84f845d5d7b71d70a17412"}, - {file = "librt-0.11.0-cp311-cp311-win32.whl", hash = "sha256:46c60b61e308eb535fbd6fa622b1ee1bb2815691c1ad9c98bf7b84952ec3bc8d"}, - {file = "librt-0.11.0-cp311-cp311-win_amd64.whl", hash = "sha256:902e546ff044f579ff1c953ff5fce97b636fe9e3943996b2177710c6ef076f73"}, - {file = "librt-0.11.0-cp311-cp311-win_arm64.whl", hash = "sha256:65ac3bc20f78aa0ee5ae84baa68917f89fef4af63e941084dd019a0d0e749f0c"}, - {file = "librt-0.11.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b87504f1690a23b9a2cca841191a04f83895d4fc2dd04df91d82b1a04ca2ad46"}, - {file = "librt-0.11.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40071fc5fe0ce8daa6de616702314a01e1250711682b0523d6ab8d4525910cb3"}, - {file = "librt-0.11.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:137e79445c896a0ea7b265f52d23954e05b64222ee1af69e2cb34219067cbb67"}, - {file = "librt-0.11.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:cca6644054e78746d8d4ef238681f9c34ff8b584fe6b988ecebb8db3b15e622a"}, - {file = "librt-0.11.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d5b0eea49f5562861ee8d757a32ef7d559c1d35be2aaaa1ec28941d74c9ffc8a"}, - {file = "librt-0.11.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0d1029d7e1ae1a7e647ed6fb5df8c4ce2dffefb7a9f5fd1376a4554d96dac09f"}, - {file = "librt-0.11.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:bc3ce6b33c5828d9e80592011a5c584cb2ce86edbc4088405f70da47dc1d1b3b"}, - {file = "librt-0.11.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:936c5995f3514a42111f20099397d8177c79b4d7e70961e396c6f5a0a3566766"}, - {file = "librt-0.11.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:9bc0ca6ad9381cbe8e4aa6e5726e4c80c78115a6e9723c599ed1d73e092bc49d"}, - {file = "librt-0.11.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:070aa8c26c0a74774317a72df8851facc7f0f012a5b406557ac56992d92e1ec8"}, - {file = "librt-0.11.0-cp312-cp312-win32.whl", hash = "sha256:6bf14feb84b05ae945277395451998c89c54d0def4070eb5c08de544930b245a"}, - {file = "librt-0.11.0-cp312-cp312-win_amd64.whl", hash = "sha256:75672f0bc524ede266287d532d7923dbce94c7514ad07627bac3d0c6d92cc4d9"}, - {file = "librt-0.11.0-cp312-cp312-win_arm64.whl", hash = "sha256:2f10cf143e4a9bb0f4f5af568a00df94a2d69ef41c2579584454bb0fe5cc642c"}, - {file = "librt-0.11.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:78dc31f7fdfe9c9d0eb0e8f42d139db230e826415bbcabd9f0e9faaaee909894"}, - {file = "librt-0.11.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:fa475675db22290c3158e1d42326d0f5a65f04f44a0e68c3630a25b53560fb9c"}, - {file = "librt-0.11.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:621db29691044bdeda22e789e482e1b0f3a985d90e3426c9c6d17606416205ea"}, - {file = "librt-0.11.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a9010e2ed5b3a9e158c5fd966b3ab7e834bb3d3aacc8f66c91dd4b57a3799230"}, - {file = "librt-0.11.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c39513d8b7477a2e1ed8c43fc21c524e8d5a0f8d4e8b7b074dbdbe7820a08e2"}, - {file = "librt-0.11.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7aef3cf1d5af86e770ab04bfd993dfc4ae8b8c17f66fb77dd4a7d50de7bbb1a3"}, - {file = "librt-0.11.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:557183ddc36babe46b27dd60facbd5adb4492181a5be887587d57cda6e092f21"}, - {file = "librt-0.11.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:83d3e1f72bd42f6c5c0b7daec530c3f829bd02db42c70b8ddf0c2d90a2459930"}, - {file = "librt-0.11.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:4ce1f21fbe589bc1afd7872dece84fb0e1144f794a288e58a10d2c54a55c43be"}, - {file = "librt-0.11.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:970b09f7044ea2b64c9da42fd3d335666518cfd1c6e8a182c95da73d0214b41e"}, - {file = "librt-0.11.0-cp313-cp313-win32.whl", hash = "sha256:78fddc31cd4d3caa897ad5d31f856b1faadc9474021ad6cb182b9018793e254e"}, - {file = "librt-0.11.0-cp313-cp313-win_amd64.whl", hash = "sha256:8ca8aa88751a775870b764e93bad5135385f563cb8dcee399abf034ea4d3cb47"}, - {file = "librt-0.11.0-cp313-cp313-win_arm64.whl", hash = "sha256:96f044bb325fd9cf1a723015638c219e9143f0dfbc0ca54c565df2b7fc748b44"}, - {file = "librt-0.11.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:4a017a95e5837dc15a8c5661d60e05daa96b90908b1aa6b7acdf443cd25c8ebd"}, - {file = "librt-0.11.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:b1ecbd9819deccc39b7542bf4d2a740d8a620694d39989e58661d3763458f8d4"}, - {file = "librt-0.11.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7da327dacd7be8f8ec36547373550744a3cc0e536d54665cd83f8bcd961200e8"}, - {file = "librt-0.11.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0dc56b1f8d06e60db362cc3fdae206681817f86ce4725d34511473487f12a34b"}, - {file = "librt-0.11.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:05fb8fb2ab90e21c8d12ea240d744ad514da9baf381ebfa70d91d20d21713175"}, - {file = "librt-0.11.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cae74872be221df4374d10fec61f93ed1513b9546ea84f2c0bf73ab3e9bd0b03"}, - {file = "librt-0.11.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:32bcc918c0148eb7e3d57385125bac7e5f9e4359d05f07448b09f6f778c2f31c"}, - {file = "librt-0.11.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:f9743fc99135d5f78d2454435615f6dec0473ca507c26ce9d92b10b562a280d3"}, - {file = "librt-0.11.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:5ba067f4aadae8fda802d91d2124c90c42195ff32d9161d3549e6d05cfe26f96"}, - {file = "librt-0.11.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:de3bf945454d032f9e390b85c4072e0a0570bf825421c8be0e71209fa65e1abe"}, - {file = "librt-0.11.0-cp314-cp314-win32.whl", hash = "sha256:d2277a05f6dcb9fd13db9566aac4fabd68c3ea1ea46ee5567d4eef8efa495a2f"}, - {file = "librt-0.11.0-cp314-cp314-win_amd64.whl", hash = "sha256:ab73e8db5e3f564d812c1f5c3a175930a5f9bc96ccb5e3b22a34d7858b401cf7"}, - {file = "librt-0.11.0-cp314-cp314-win_arm64.whl", hash = "sha256:aea3caa317752e3a466fa8af45d91ee0ea8c7fdd96e42b0a8dd9b76a7931eba1"}, - {file = "librt-0.11.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:d1b36540d7aaf9b9101b3a6f376c8d8e9f7a9aec93ed05918f2c69d493ffef72"}, - {file = "librt-0.11.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:efbb343ab2ce3540f4ecbe6315d677ed70f37cd9a72b1e58066c918ca83acbaa"}, - {file = "librt-0.11.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:aa0dd688aab3f7914d3e6e5e3554978e0383312fb8e771d84be008a35b9ee548"}, - {file = "librt-0.11.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f5fb36b8c6c63fdcbb1d526d94c0d1331610d43f4118cc1beb4efef4f3faacb2"}, - {file = "librt-0.11.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4a9a237d13addb93715b6fee74023d5ee3469b53fce527626c0e088aa585805f"}, - {file = "librt-0.11.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5ddd17bd87b2c56ddd60e546a7984a2e64c4e8eab92fb4cf3830a48ad5469d51"}, - {file = "librt-0.11.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bd43992b4473d42f12ff9e68326079f0696d9d4e6000e8f39a0238d482ba6ee2"}, - {file = "librt-0.11.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:f8e3e8056dd674e279741485e2e512d6e9a751c7455809d0114e6ebf8d781085"}, - {file = "librt-0.11.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:c1f708d8ae9c56cf38a903c44297243d2ec83fd82b396b977e0144a3e76217e3"}, - {file = "librt-0.11.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0add982e0e7b9fc14cf4b33789d5f13f66581889b88c2f58099f6ce8f92617bd"}, - {file = "librt-0.11.0-cp314-cp314t-win32.whl", hash = "sha256:2b481d846ac894c4e8403c5fd0e87c5d11d6499e404b474602508a224ff531c8"}, - {file = "librt-0.11.0-cp314-cp314t-win_amd64.whl", hash = "sha256:28edb433edde181112a908c78907af28f964eabc15f4dd16c9d66c834302677c"}, - {file = "librt-0.11.0-cp314-cp314t-win_arm64.whl", hash = "sha256:dee008f20b542e3cd162ba338a7f9ec0f6d23d395f66fe8aeeec3c9d067ea253"}, - {file = "librt-0.11.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:6bd72d903911d995ab666dbd1871f8b1e80925a699af8063fbf50053329fb05f"}, - {file = "librt-0.11.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0ef69ac715f3cd8e5cd252cb2aebfa72c015492aacc339d5d7bf8fef3c62c677"}, - {file = "librt-0.11.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:624a40c4a4ad7773315c287276cd024509b2c66ff5904f504bfc08d2c70293ab"}, - {file = "librt-0.11.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:41dc19fe150b69716c8ece4f76773a9e8813fe3e35e032a58b4d46423fb8d7c0"}, - {file = "librt-0.11.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e8bd98ea9c47ae90b319a087ab28dac493f1ffbc1ecd1f28fcdbf3b7e1108d1"}, - {file = "librt-0.11.0-cp39-cp39-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:84308fc49423ce6475d1c5d1985cd69a8ca9f0325fc7d5f81bb690a3f3625d4e"}, - {file = "librt-0.11.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:ff0fbaf5f44a21beeb0110f2ab64f45135a9536a834b79c0d1ef018f2786bbfa"}, - {file = "librt-0.11.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:9c028a9442a18e266955d364ce42259136e79a7ba14d773e0d778d5f70cd56f1"}, - {file = "librt-0.11.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9f1692105a02bcf853f355032a5fdc5494358ef83d8fd22d16de375c85cec3f5"}, - {file = "librt-0.11.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7a80a71e1fda83cc752a9141e87aae7fef279538597564d670e9ce513f286192"}, - {file = "librt-0.11.0-cp39-cp39-win32.whl", hash = "sha256:140695816ddf3c86eb972981a26f35efd871c44b0c3aed44c8cd01749386617f"}, - {file = "librt-0.11.0-cp39-cp39-win_amd64.whl", hash = "sha256:92f7ff819c197fc30473190a12c2856f325ac90aabfccbeb2072d28cc2e234e3"}, - {file = "librt-0.11.0.tar.gz", hash = "sha256:075dc3ef4458a278e0195cbf6ac9d38808d9b906c5a6c7f7f79c3888276a3fb1"}, + {file = "librt-0.16.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:96f576f2711f8519152ec76d0e599243555c1f07679fa73606ca8c8c868c0be6"}, + {file = "librt-0.16.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2bec3818c7da7c96ceae0ef5915a3d16c52dd08f3ea913bf1fe8568c447c7978"}, + {file = "librt-0.16.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:64c79520414a3fdfc6aabd7593e6169afa14d5f8d9908d4b498db068868b08dd"}, + {file = "librt-0.16.0-cp310-cp310-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:f81b5b19ce748ef68d4746656b7929762eb2fe99269b266e4be07e2ee4de7144"}, + {file = "librt-0.16.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:c71d1b76210a36729fedfc5115069b50a3d8619054745f8758fe5d6f19e86671"}, + {file = "librt-0.16.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:473eebc7866bb0a0c8849a292b5e7157c1aba5d14d0f0f610c52158d6d964262"}, + {file = "librt-0.16.0-cp310-cp310-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4eb1313a19847089ee81e88742abedf285c60538816640b99742d8534b81d26a"}, + {file = "librt-0.16.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ebefd60b42e2a82b32d136bb5f7c94eadfcd29f772b547df6f3291d1ed855a1c"}, + {file = "librt-0.16.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6c5da27e8056439f927ea896735da60e616c477a8293feaa3233d4e7781a6726"}, + {file = "librt-0.16.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:67e718c7a43f8db325abbbf1404e2d535f12f8f7a1a82259568385cc5274b82a"}, + {file = "librt-0.16.0-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:314e703f0c19320dc8094e7a784b9cf29e1b67402515abf580069a6363c0b4f1"}, + {file = "librt-0.16.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:943c6bbecbdf7fa575a4f2952fcfd848c88ef95507c3fca411e89d4ac3ff8143"}, + {file = "librt-0.16.0-cp310-cp310-win32.whl", hash = "sha256:7cc365f006891afb006b52d5ee5ee74c09306ffa20e2f8705a32a4450af2f3ba"}, + {file = "librt-0.16.0-cp310-cp310-win_amd64.whl", hash = "sha256:0314058469f4d2fd279ce7c62ac274ac82c3918ef7db62ef0697c4c359370155"}, + {file = "librt-0.16.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:fe4372c52d4849096c6cc1cda2817d293ec51440c890474ed59ef38d46556f18"}, + {file = "librt-0.16.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c72c5295a84bd249526da9bdca38f2e176d15c31c13bb0063c5053f4ca023421"}, + {file = "librt-0.16.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:be56ba9c884143495b517f23fe794ae367d58cd89ea0fdd6d437e3c024a87f9f"}, + {file = "librt-0.16.0-cp311-cp311-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:ef46c1a29ffb8c72e882e22618ec618778eacd0578fb22c6e7cf9c11d15f357b"}, + {file = "librt-0.16.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d3c94211ee0c4f8d649ec06b7c115c0ec4eadb873a0e3154ca15cef3f814b071"}, + {file = "librt-0.16.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:94aed6a8308818b91677957d1bd03188869cd7aeb23c5dba7912a6c0402f7602"}, + {file = "librt-0.16.0-cp311-cp311-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:349c0bcb87ebd07481b6ff781e25cdc699723dbe2212e57dabb27f7a13b7b87d"}, + {file = "librt-0.16.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:001bfd59a7d45b17e3e75f2a8c6405280b35e7b84471792778e718c4f368950e"}, + {file = "librt-0.16.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:28e038895b998d7a0c7798922ce8a1dc157675df5cf1c9ef0aca809ed804b7a1"}, + {file = "librt-0.16.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:0dbe4096a7ecc00fa835d24510ad8545a4efef738dac96e0e63516783ccde905"}, + {file = "librt-0.16.0-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:5cd5b092441053364af968ea12084692cb9d4a22f3ce9524e377880bf028761e"}, + {file = "librt-0.16.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3ddeb3c9dedb461bb457c6c7d9aa7fbf35329da313d1a7543d00c8d0f3473c96"}, + {file = "librt-0.16.0-cp311-cp311-win32.whl", hash = "sha256:e05108e0849966f53a8d2d3112a7af881d0efaa479bc735bba91108f9f2350a7"}, + {file = "librt-0.16.0-cp311-cp311-win_amd64.whl", hash = "sha256:5f49cff01bd608ef7d97104cb035c75455e79c2d70bf4a506cf773338ac1860d"}, + {file = "librt-0.16.0-cp311-cp311-win_arm64.whl", hash = "sha256:1d28ae980ae2218f9c5b95d191e947296f918c9bf0b400d467a9430275bbe678"}, + {file = "librt-0.16.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fe52bf4641069e7978a14253b036cb9002def1926317e710f2e249f8a8c47742"}, + {file = "librt-0.16.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5bcc2c4726ced915b00de0c9856a4eeabfb3fddb93e10e0b8f735b7709358b6d"}, + {file = "librt-0.16.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:ff7baa55f8e7c69851419e50a666015d02a74198716fd45c0125a2112e0a389f"}, + {file = "librt-0.16.0-cp312-cp312-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:b95d5d92ab83d39e760a52091bb1baba664f3a2351e39b1e16801e5747c2f0e9"}, + {file = "librt-0.16.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:b6d085d70bce51d43c5c7c36d63490770180d8779e71c49305c87b4213918de7"}, + {file = "librt-0.16.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:36e53948e99bbe3ffea257124cfcae1cfb01831555c9a9c903c9f9a72db7fd07"}, + {file = "librt-0.16.0-cp312-cp312-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:54d11f726aae9df5a6ffbbf0a03a52449bbac84a53ef03669cb41cdfd4ae41bf"}, + {file = "librt-0.16.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:4323193ac0cd025f85af531df8ba91bf24d1973b401697347a6282e8fd3fcf5e"}, + {file = "librt-0.16.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e42f8e098b9c5396fefa05fb1cc7e33b0e08fc51da106b5de4a45fd22aac6743"}, + {file = "librt-0.16.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:39ec1d5a14e37baf1450a6cabf03fe552340808bf1ad9d71824ab90117716459"}, + {file = "librt-0.16.0-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:d1aabe3925cbb4a08d15b7b20ba4011b53019da0c4173a25155139b7b1baed65"}, + {file = "librt-0.16.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:300c3ffdc459f4a779a8411ecb188e3ac0b1ff3a3a7b099642555dedae06c69b"}, + {file = "librt-0.16.0-cp312-cp312-win32.whl", hash = "sha256:c17194318e4c0c0348b36f36c2ec7534436fe0a4c15582403162a4f08c80797a"}, + {file = "librt-0.16.0-cp312-cp312-win_amd64.whl", hash = "sha256:25a58a19ea8d83b68209f04912df765e9260635ef77646542ed4b4abe6bc7940"}, + {file = "librt-0.16.0-cp312-cp312-win_arm64.whl", hash = "sha256:f7be7cf555bc30ec12622e9447299cc4a9b8ff307548b634794353db0c2065dc"}, + {file = "librt-0.16.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:c5e6144e68b577f157519f2ba88ca20e3ed61c29b00e5cdfa76cd2d45acf059a"}, + {file = "librt-0.16.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:33f41443a1f4e1f099331b3d8120e409fbff84b9760bc1cc9ea496f37ddaa5cc"}, + {file = "librt-0.16.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7e510b7770bee609617a3374a96548eb114cae048023e3f049ee449e7ff2db32"}, + {file = "librt-0.16.0-cp313-cp313-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:efc49c462d4516b8a58b00b490078fa64689fd1fe66970cc190131d7afb8027e"}, + {file = "librt-0.16.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:92caf82ebef5e12d21c72242b70d1e92536f1711cf2a727a4c276de4b4469087"}, + {file = "librt-0.16.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:17bac7f7a16b328fff77e440287693eb017abde913595b5827ebccbc21ecd8a6"}, + {file = "librt-0.16.0-cp313-cp313-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:5b976054553670829985ed767feb78fb6bcede0175327c4844dd5c281c1be659"}, + {file = "librt-0.16.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0058f9d68721094105917254c72ac0569117bb7b13b9769cf45d26d89f9d21cd"}, + {file = "librt-0.16.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:30b7beaf3f4487b7d8adef1f158b49067cb4d5a19fa7a3bf31a4e7a820e435c5"}, + {file = "librt-0.16.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:468df902df016a06eb0e40b0747dc8d14e47d7a38b18b63b1fb167d85cb94d63"}, + {file = "librt-0.16.0-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:aea7b1f2b125dad5de85f049136651bff256c883c65e6b9209b2da0a1ac3cdef"}, + {file = "librt-0.16.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a8afb6557920860b7a3a596eb804cf37e09e7cf8a803db2478c202acc72d8c2e"}, + {file = "librt-0.16.0-cp313-cp313-pyemscripten_2025_0_wasm32.whl", hash = "sha256:77c7a2b4fe2c1369e0d5aa1cade26740a7b14be32fbc9a5535d617d20065c39d"}, + {file = "librt-0.16.0-cp313-cp313-win32.whl", hash = "sha256:02d89c813d5ff74b17df72d3a34819d132cd168e56b81bf755b809bd9e46b8c4"}, + {file = "librt-0.16.0-cp313-cp313-win_amd64.whl", hash = "sha256:14ed6ebe3e4f85f326d7920011ad30ff49ed9334e62cf88caef9ba973d9e3a92"}, + {file = "librt-0.16.0-cp313-cp313-win_arm64.whl", hash = "sha256:83d4041a3d9b2fd053a8a4e1f22878b3e5833e2712956382d5c048d791454e91"}, + {file = "librt-0.16.0-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:931a0bb0fcac88f263e269e46eb30ba8e21402cd3c62ca40cb97034c0693fab1"}, + {file = "librt-0.16.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:1bc17e54e5305f8d40b7ca203671ff5a9e59c1d0f8ea0f625dcca53a3984de11"}, + {file = "librt-0.16.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:877698bf6bca5721d8be345f2fe09778e40ecadea8b58c73075f2b1a53666bf2"}, + {file = "librt-0.16.0-cp314-cp314-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:5981c011b306781ce561e18e14230a14524a3d8109b97553666c942c18f31a96"}, + {file = "librt-0.16.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:afced3dfc17cd805ecf7a3d77996a71cf5f2c75aa66eb0c21a9930f4fc992f86"}, + {file = "librt-0.16.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ca8052401c55d7511dda6760719fda7618067e83535d7d0010096d216c34b667"}, + {file = "librt-0.16.0-cp314-cp314-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:1e511762a074005bb0aa569166779834e75e438370226930d0ce1866d4b6a33b"}, + {file = "librt-0.16.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:f1e8591bd8a5a628cd7f07954c6a1592359a878bf032957a8e9057a41d644311"}, + {file = "librt-0.16.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:a4aaefb4ba6c07e1aeebb2795c8958148f1d6f9af3b555b53d23d766edb6d67a"}, + {file = "librt-0.16.0-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:d92db7a0f6aee44f1baee94750457e8d2d1c6ccea41842de6268d34e8dc7eddd"}, + {file = "librt-0.16.0-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:378dfaffb38e59c24a87cde5713cd865d51ff7383fa12947f3907f306ea1ca55"}, + {file = "librt-0.16.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:3e0c39bdc85370422e8b637be76eb1fd07d30967551b03e62267dd156f553152"}, + {file = "librt-0.16.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl", hash = "sha256:1b384b90ab79a7bc30b566895809a636e0666f21f3cf12b54823d025b7e83839"}, + {file = "librt-0.16.0-cp314-cp314-win32.whl", hash = "sha256:52327da75a94012e7f932f913d20d3876bed3c102be00e6c3e8600ff7bdd58a7"}, + {file = "librt-0.16.0-cp314-cp314-win_amd64.whl", hash = "sha256:3f0b8114c44b2ac06ff5dacd08e07e8e807ff4f46083f2a1602685122559be41"}, + {file = "librt-0.16.0-cp314-cp314-win_arm64.whl", hash = "sha256:8caf96a4ef8fb27d0ac0d1ad8337d26a240acd4a02fe4345d0a8f264753e8f99"}, + {file = "librt-0.16.0-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:953107e2f68d0f3512c48f898b0dbf0ce5cc52bba0f318d847c985dc555ee4cc"}, + {file = "librt-0.16.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:ad37d5b9abd49c9a655dcda7ea52a8a752884062ef1ee71ae17c2f2a0f81fe6a"}, + {file = "librt-0.16.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:2c4aa329c17bd1aaea4f6e89335d8ccd494b3a5830b6654462273e50e11023f0"}, + {file = "librt-0.16.0-cp314-cp314t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:0ead24d2562a49473dddd9efef8581f020007eb0054389c3ee3ffad38b1ca4c9"}, + {file = "librt-0.16.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:02118f56a9c36ddd07dfd9b919d9ecc117ba20a90987d56aa4c429fa34509188"}, + {file = "librt-0.16.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:4e29522c62e28595ff7e324c6834ade51127707f0e255b18d1c1cf03d39c1048"}, + {file = "librt-0.16.0-cp314-cp314t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:3ff4b2367926b69c6215635902cccb04048e73094e9862900d27cb2c6bbff143"}, + {file = "librt-0.16.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:c6f1b27bf1632a7e016af9f145f82be95e1edd7721a646505c21059257cb5a04"}, + {file = "librt-0.16.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:5696d7f52e7b37217cb3a8f92c744fe835942602fdd4c1a8bc4741d3bfdce15e"}, + {file = "librt-0.16.0-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:6072e92dd876ff6ceeb6cf371e35e51f479349837391341f479b08df4564242b"}, + {file = "librt-0.16.0-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:39ca4f2f2fe05de8e63493da592d84311adabe5bef52b193851981da9816b302"}, + {file = "librt-0.16.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:f9807485a908f00355820f18e91e045ffdcdc5adb68aaec40a1e2b88c5f7bba1"}, + {file = "librt-0.16.0-cp314-cp314t-win32.whl", hash = "sha256:94be5cb7bca4df6201f4183e9e4fa2086c655283d20b38cd84500a69057575a7"}, + {file = "librt-0.16.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d46ca272b251d033dd4527b0dec5f261a28a52bd5fa0f99c117b0a1f8588cc2d"}, + {file = "librt-0.16.0-cp314-cp314t-win_arm64.whl", hash = "sha256:b9d6d4b14e92d876f8026b54c20c445f36425214c1081dc76f74e40db386b82b"}, + {file = "librt-0.16.0-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:6fe436af2eaf630474f491af5d032cbe45f93fcff5c3b9fe4ab194a7255b20ff"}, + {file = "librt-0.16.0-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:8ff5d26c529336be9bd7ae04483235d77778ee7d6444a95353102b542601ce81"}, + {file = "librt-0.16.0-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:909d8e3c1faee44cb762b1c519ff8613dcc5ceae5c99987a00917b5a31fd1d6a"}, + {file = "librt-0.16.0-cp315-cp315-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:6d4a64283ee61824b5790de882bc68e2d9d7a5143537cb7a966f7354f71646d4"}, + {file = "librt-0.16.0-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5810ba811297fdf37a1531a57667cb8ace0842013ca8606bf9eb7c24cf4be154"}, + {file = "librt-0.16.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e56aaf8c167548dc8e5d6f3bd0f48dcdd299a23c73be3f744aab79d99e9c7f5d"}, + {file = "librt-0.16.0-cp315-cp315-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f36c58e33b304b525c6c9c5076399c6ebf1109e17b9051a05a407b091b9215b"}, + {file = "librt-0.16.0-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:242e00b3d4fa37c3d3c1ca5f5c9adb7d909ddb1eac9c41f2787320d00caa0af2"}, + {file = "librt-0.16.0-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:0253721561787b8df8443eb347b7a6461015354e5bdd37ee38a41fef220d2bb0"}, + {file = "librt-0.16.0-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:3e483a8d69ede8067db70c0e83007423b6925de6fd53afed01d66160f2e9398c"}, + {file = "librt-0.16.0-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:69ba927445cfaaffb4081003ef5224c55a5c2ab67ef956f416ef744916e44121"}, + {file = "librt-0.16.0-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:d6a365f2ab45a984d0e00eee0dd17f599ceab8cadab6ea07b6111c8132fc0e42"}, + {file = "librt-0.16.0-cp315-cp315-pyemscripten_2026_5_wasm32.whl", hash = "sha256:f01f3805f2dae4781c0c34b440e31740d082950bdaf89a6f601ad589a28af57a"}, + {file = "librt-0.16.0-cp315-cp315-win32.whl", hash = "sha256:b0e3e721c75d2e79a76d4422c79d7ba705fe1bbafec907037fe7a657a480a0e3"}, + {file = "librt-0.16.0-cp315-cp315-win_amd64.whl", hash = "sha256:bc02954b1295de798bbdb0b4e2d8a28c2117de8b5c73dcbeb27dc32572dfb971"}, + {file = "librt-0.16.0-cp315-cp315-win_arm64.whl", hash = "sha256:c5db585d43449a5f54303d4b2774e45e1babd975cfe1630a3d708c0b80c3e560"}, + {file = "librt-0.16.0-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:f06c689cb14afd9b612727553a5ec5a40febf113ca41c4413a2b0b334285884b"}, + {file = "librt-0.16.0-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:13b4e8aba90b0b1c82474e9844aa9ffe7ad3faa484350e1da64cb8188d903134"}, + {file = "librt-0.16.0-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:5a269c46ae327d8e6f8c1f85f7516cb52c0fa48127565a1105a4f4a05ff2a0b4"}, + {file = "librt-0.16.0-cp315-cp315t-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:a33e0dae1f8592146a4764d54ce842b278732d21a84e17c3bbe6b1bc158a2248"}, + {file = "librt-0.16.0-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:47ada6ea32636492c61aa8ad27ae3b9404bfe7a97e3ba946d1984236cc741da0"}, + {file = "librt-0.16.0-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c43bd6e642d8a248c114327f98dd25ac5a7cb5aa168ef02f0559b91874df16b8"}, + {file = "librt-0.16.0-cp315-cp315t-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c3d1bb7841a816ace6449bb26d3f9560dbfa20e71c568d23f0f62bf1e68f50b1"}, + {file = "librt-0.16.0-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:3931f7a3db322e7f44e02a280e3949326ce9579ad388ee8d691dc7c76da9fb70"}, + {file = "librt-0.16.0-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:f4462528b6000afe8f16907b5c7c2553abf1df005ba5140e6eb394541c3624c3"}, + {file = "librt-0.16.0-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:80039ba9b6a7d5f1a0175a4cca6bbefead87bd854c80abad1cb30afe47a830db"}, + {file = "librt-0.16.0-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:7a1d272724b581bb6bc769dfdafed6da2ecc9886ba2450311de55a4ac2e1e9cd"}, + {file = "librt-0.16.0-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:fbe4fb8c5445f7496d7f7f6bb0807875d09d47e6771ffa175fb2df2895fb86ba"}, + {file = "librt-0.16.0-cp315-cp315t-win32.whl", hash = "sha256:375bfe6b572a8f6cfc398709356046173bf27e64c4c5edaf5f7062f051fb4bf9"}, + {file = "librt-0.16.0-cp315-cp315t-win_amd64.whl", hash = "sha256:bd3150023d3dc2bc70f3784e59ffa1140d56ddba3d8125b3d6f9f85221279bfc"}, + {file = "librt-0.16.0-cp315-cp315t-win_arm64.whl", hash = "sha256:8ceafb70f2a4f0826f11031942e59c0728fd98da112dc346d4352bde1e486866"}, + {file = "librt-0.16.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:e1967e36ac4cae0c7e9615ad32e1a513cdacff79f9e8afb28bedc91caf48b4f3"}, + {file = "librt-0.16.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:20fe0bf9053885e21c62b3e091fb5e73e1c54d1daf2e70eb388d70763bcd4220"}, + {file = "librt-0.16.0-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a63610fa76524edfa605b5b259a603915c7a6e10e54f003e5503030506e81de"}, + {file = "librt-0.16.0-cp39-cp39-manylinux2014_i686.manylinux_2_17_i686.manylinux_2_28_i686.whl", hash = "sha256:845a511b60ca43b9880dcc84a9784c891d6a2098c829130b320846c69c9c0c68"}, + {file = "librt-0.16.0-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:d608f0bf3b8cbddd0067fe02cb8cab7d13e8eb9386b23a1843d4363044fd9e22"}, + {file = "librt-0.16.0-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:df183721229ae51eef90108c115b43e98cb169b6155d34480338e5fc6616df00"}, + {file = "librt-0.16.0-cp39-cp39-manylinux_2_34_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:4b6183e2e2e0ee00aac2ec07c7f7d151c97e85666b304f574b71cff0f9fccc4e"}, + {file = "librt-0.16.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:273d00be33792a15189331df10f1f1331621b043881e66c6c4377f7f776e1291"}, + {file = "librt-0.16.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:aa9357a1b4d4fc787bb718a59cb1112c28c8a976d6bfa268b71cc0a4ab8f3a94"}, + {file = "librt-0.16.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:e9ce0bc440e7fd09b5f51f372f0f6640658f854b8fb05260f819cc669c93c42d"}, + {file = "librt-0.16.0-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:6c8893eae2fd13c5488d94056f3e6e5cf3142bfb1c4acaf136cb33d760c5964b"}, + {file = "librt-0.16.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7393c9a48dcce4817dbd4b0d8ff6237efe9b0a0609f5b0adaef315f8541726b5"}, + {file = "librt-0.16.0-cp39-cp39-win32.whl", hash = "sha256:71b93b42784e25b975079573c642a8fedb049a7bb31d70a51721b1666b3b2ced"}, + {file = "librt-0.16.0-cp39-cp39-win_amd64.whl", hash = "sha256:5750a105b42a416f930edc59054927a406effb2550cd5bab92ad7a5842ed5d05"}, + {file = "librt-0.16.0.tar.gz", hash = "sha256:ac38d6d8d66bf3d744148dbbc0b8e193e195a51e364ed55e224631f5721891fc"}, ] [[package]] @@ -1393,101 +1530,163 @@ testing = ["coverage", "pytest", "pytest-cov", "pytest-regressions", "pytest-tim [[package]] name = "markupsafe" -version = "3.0.3" +version = "3.0.4" description = "Safely add untrusted strings to HTML/XML markup." optional = false python-versions = ">=3.9" groups = ["dev", "docs"] files = [ - {file = "markupsafe-3.0.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2f981d352f04553a7171b8e44369f2af4055f888dfb147d55e42d29e29e74559"}, - {file = "markupsafe-3.0.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e1c1493fb6e50ab01d20a22826e57520f1284df32f2d8601fdd90b6304601419"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1ba88449deb3de88bd40044603fafffb7bc2b055d626a330323a9ed736661695"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f42d0984e947b8adf7dd6dde396e720934d12c506ce84eea8476409563607591"}, - {file = "markupsafe-3.0.3-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c0c0b3ade1c0b13b936d7970b1d37a57acde9199dc2aecc4c336773e1d86049c"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0303439a41979d9e74d18ff5e2dd8c43ed6c6001fd40e5bf2e43f7bd9bbc523f"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:d2ee202e79d8ed691ceebae8e0486bd9a2cd4794cec4824e1c99b6f5009502f6"}, - {file = "markupsafe-3.0.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:177b5253b2834fe3678cb4a5f0059808258584c559193998be2601324fdeafb1"}, - {file = "markupsafe-3.0.3-cp310-cp310-win32.whl", hash = "sha256:2a15a08b17dd94c53a1da0438822d70ebcd13f8c3a95abe3a9ef9f11a94830aa"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_amd64.whl", hash = "sha256:c4ffb7ebf07cfe8931028e3e4c85f0357459a3f9f9490886198848f4fa002ec8"}, - {file = "markupsafe-3.0.3-cp310-cp310-win_arm64.whl", hash = "sha256:e2103a929dfa2fcaf9bb4e7c091983a49c9ac3b19c9061b6d5427dd7d14d81a1"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:1cc7ea17a6824959616c525620e387f6dd30fec8cb44f649e31712db02123dad"}, - {file = "markupsafe-3.0.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4bd4cd07944443f5a265608cc6aab442e4f74dff8088b0dfc8238647b8f6ae9a"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6b5420a1d9450023228968e7e6a9ce57f65d148ab56d2313fcd589eee96a7a50"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0bf2a864d67e76e5c9a34dc26ec616a66b9888e25e7b9460e1c76d3293bd9dbf"}, - {file = "markupsafe-3.0.3-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:bc51efed119bc9cfdf792cdeaa4d67e8f6fcccab66ed4bfdd6bde3e59bfcbb2f"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:068f375c472b3e7acbe2d5318dea141359e6900156b5b2ba06a30b169086b91a"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:7be7b61bb172e1ed687f1754f8e7484f1c8019780f6f6b0786e76bb01c2ae115"}, - {file = "markupsafe-3.0.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:f9e130248f4462aaa8e2552d547f36ddadbeaa573879158d721bbd33dfe4743a"}, - {file = "markupsafe-3.0.3-cp311-cp311-win32.whl", hash = "sha256:0db14f5dafddbb6d9208827849fad01f1a2609380add406671a26386cdf15a19"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_amd64.whl", hash = "sha256:de8a88e63464af587c950061a5e6a67d3632e36df62b986892331d4620a35c01"}, - {file = "markupsafe-3.0.3-cp311-cp311-win_arm64.whl", hash = "sha256:3b562dd9e9ea93f13d53989d23a7e775fdfd1066c33494ff43f5418bc8c58a5c"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d53197da72cc091b024dd97249dfc7794d6a56530370992a5e1a08983ad9230e"}, - {file = "markupsafe-3.0.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1872df69a4de6aead3491198eaf13810b565bdbeec3ae2dc8780f14458ec73ce"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3a7e8ae81ae39e62a41ec302f972ba6ae23a5c5396c8e60113e9066ef893da0d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d6dd0be5b5b189d31db7cda48b91d7e0a9795f31430b7f271219ab30f1d3ac9d"}, - {file = "markupsafe-3.0.3-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:94c6f0bb423f739146aec64595853541634bde58b2135f27f61c1ffd1cd4d16a"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:be8813b57049a7dc738189df53d69395eba14fb99345e0a5994914a3864c8a4b"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:83891d0e9fb81a825d9a6d61e3f07550ca70a076484292a70fde82c4b807286f"}, - {file = "markupsafe-3.0.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:77f0643abe7495da77fb436f50f8dab76dbc6e5fd25d39589a0f1fe6548bfa2b"}, - {file = "markupsafe-3.0.3-cp312-cp312-win32.whl", hash = "sha256:d88b440e37a16e651bda4c7c2b930eb586fd15ca7406cb39e211fcff3bf3017d"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_amd64.whl", hash = "sha256:26a5784ded40c9e318cfc2bdb30fe164bdb8665ded9cd64d500a34fb42067b1c"}, - {file = "markupsafe-3.0.3-cp312-cp312-win_arm64.whl", hash = "sha256:35add3b638a5d900e807944a078b51922212fb3dedb01633a8defc4b01a3c85f"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e1cf1972137e83c5d4c136c43ced9ac51d0e124706ee1c8aa8532c1287fa8795"}, - {file = "markupsafe-3.0.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:116bb52f642a37c115f517494ea5feb03889e04df47eeff5b130b1808ce7c219"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:133a43e73a802c5562be9bbcd03d090aa5a1fe899db609c29e8c8d815c5f6de6"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:ccfcd093f13f0f0b7fdd0f198b90053bf7b2f02a3927a30e63f3ccc9df56b676"}, - {file = "markupsafe-3.0.3-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:509fa21c6deb7a7a273d629cf5ec029bc209d1a51178615ddf718f5918992ab9"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:a4afe79fb3de0b7097d81da19090f4df4f8d3a2b3adaa8764138aac2e44f3af1"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:795e7751525cae078558e679d646ae45574b47ed6e7771863fcc079a6171a0fc"}, - {file = "markupsafe-3.0.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8485f406a96febb5140bfeca44a73e3ce5116b2501ac54fe953e488fb1d03b12"}, - {file = "markupsafe-3.0.3-cp313-cp313-win32.whl", hash = "sha256:bdd37121970bfd8be76c5fb069c7751683bdf373db1ed6c010162b2a130248ed"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_amd64.whl", hash = "sha256:9a1abfdc021a164803f4d485104931fb8f8c1efd55bc6b748d2f5774e78b62c5"}, - {file = "markupsafe-3.0.3-cp313-cp313-win_arm64.whl", hash = "sha256:7e68f88e5b8799aa49c85cd116c932a1ac15caaa3f5db09087854d218359e485"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:218551f6df4868a8d527e3062d0fb968682fe92054e89978594c28e642c43a73"}, - {file = "markupsafe-3.0.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:3524b778fe5cfb3452a09d31e7b5adefeea8c5be1d43c4f810ba09f2ceb29d37"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4e885a3d1efa2eadc93c894a21770e4bc67899e3543680313b09f139e149ab19"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8709b08f4a89aa7586de0aadc8da56180242ee0ada3999749b183aa23df95025"}, - {file = "markupsafe-3.0.3-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b8512a91625c9b3da6f127803b166b629725e68af71f8184ae7e7d54686a56d6"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9b79b7a16f7fedff2495d684f2b59b0457c3b493778c9eed31111be64d58279f"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:12c63dfb4a98206f045aa9563db46507995f7ef6d83b2f68eda65c307c6829eb"}, - {file = "markupsafe-3.0.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:8f71bc33915be5186016f675cd83a1e08523649b0e33efdb898db577ef5bb009"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win32.whl", hash = "sha256:69c0b73548bc525c8cb9a251cddf1931d1db4d2258e9599c28c07ef3580ef354"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_amd64.whl", hash = "sha256:1b4b79e8ebf6b55351f0d91fe80f893b4743f104bff22e90697db1590e47a218"}, - {file = "markupsafe-3.0.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ad2cf8aa28b8c020ab2fc8287b0f823d0a7d8630784c31e9ee5edea20f406287"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:eaa9599de571d72e2daf60164784109f19978b327a3910d3e9de8c97b5b70cfe"}, - {file = "markupsafe-3.0.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c47a551199eb8eb2121d4f0f15ae0f923d31350ab9280078d1e5f12b249e0026"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f34c41761022dd093b4b6896d4810782ffbabe30f2d443ff5f083e0cbbb8c737"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:457a69a9577064c05a97c41f4e65148652db078a3a509039e64d3467b9e7ef97"}, - {file = "markupsafe-3.0.3-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e8afc3f2ccfa24215f8cb28dcf43f0113ac3c37c2f0f0806d8c70e4228c5cf4d"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:ec15a59cf5af7be74194f7ab02d0f59a62bdcf1a537677ce67a2537c9b87fcda"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:0eb9ff8191e8498cca014656ae6b8d61f39da5f95b488805da4bb029cccbfbaf"}, - {file = "markupsafe-3.0.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:2713baf880df847f2bece4230d4d094280f4e67b1e813eec43b4c0e144a34ffe"}, - {file = "markupsafe-3.0.3-cp314-cp314-win32.whl", hash = "sha256:729586769a26dbceff69f7a7dbbf59ab6572b99d94576a5592625d5b411576b9"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_amd64.whl", hash = "sha256:bdc919ead48f234740ad807933cdf545180bfbe9342c2bb451556db2ed958581"}, - {file = "markupsafe-3.0.3-cp314-cp314-win_arm64.whl", hash = "sha256:5a7d5dc5140555cf21a6fefbdbf8723f06fcd2f63ef108f2854de715e4422cb4"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:1353ef0c1b138e1907ae78e2f6c63ff67501122006b0f9abad68fda5f4ffc6ab"}, - {file = "markupsafe-3.0.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1085e7fbddd3be5f89cc898938f42c0b3c711fdcb37d75221de2666af647c175"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1b52b4fb9df4eb9ae465f8d0c228a00624de2334f216f178a995ccdcf82c4634"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:fed51ac40f757d41b7c48425901843666a6677e3e8eb0abcff09e4ba6e664f50"}, - {file = "markupsafe-3.0.3-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f190daf01f13c72eac4efd5c430a8de82489d9cff23c364c3ea822545032993e"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:e56b7d45a839a697b5eb268c82a71bd8c7f6c94d6fd50c3d577fa39a9f1409f5"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:f3e98bb3798ead92273dc0e5fd0f31ade220f59a266ffd8a4f6065e0a3ce0523"}, - {file = "markupsafe-3.0.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:5678211cb9333a6468fb8d8be0305520aa073f50d17f089b5b4b477ea6e67fdc"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win32.whl", hash = "sha256:915c04ba3851909ce68ccc2b8e2cd691618c4dc4c4232fb7982bca3f41fd8c3d"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_amd64.whl", hash = "sha256:4faffd047e07c38848ce017e8725090413cd80cbc23d86e55c587bf979e579c9"}, - {file = "markupsafe-3.0.3-cp314-cp314t-win_arm64.whl", hash = "sha256:32001d6a8fc98c8cb5c947787c5d08b0a50663d139f1305bac5885d98d9b40fa"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15d939a21d546304880945ca1ecb8a039db6b4dc49b2c5a400387cdae6a62e26"}, - {file = "markupsafe-3.0.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f71a396b3bf33ecaa1626c255855702aca4d3d9fea5e051b41ac59a9c1c41edc"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0f4b68347f8c5eab4a13419215bdfd7f8c9b19f2b25520968adfad23eb0ce60c"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:e8fc20152abba6b83724d7ff268c249fa196d8259ff481f3b1476383f8f24e42"}, - {file = "markupsafe-3.0.3-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:949b8d66bc381ee8b007cd945914c721d9aba8e27f71959d750a46f7c282b20b"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:3537e01efc9d4dccdf77221fb1cb3b8e1a38d5428920e0657ce299b20324d758"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:591ae9f2a647529ca990bc681daebdd52c8791ff06c2bfa05b65163e28102ef2"}, - {file = "markupsafe-3.0.3-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:a320721ab5a1aba0a233739394eb907f8c8da5c98c9181d1161e77a0c8e36f2d"}, - {file = "markupsafe-3.0.3-cp39-cp39-win32.whl", hash = "sha256:df2449253ef108a379b8b5d6b43f4b1a8e81a061d6537becd5582fba5f9196d7"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_amd64.whl", hash = "sha256:7c3fb7d25180895632e5d3148dbdc29ea38ccb7fd210aa27acbd1201a1902c6e"}, - {file = "markupsafe-3.0.3-cp39-cp39-win_arm64.whl", hash = "sha256:38664109c14ffc9e7437e86b4dceb442b0096dfe3541d7864d9cbe1da4cf36c8"}, - {file = "markupsafe-3.0.3.tar.gz", hash = "sha256:722695808f4b6457b320fdc131280796bdceb04ab50fe1795cd540799ebe1698"}, + {file = "markupsafe-3.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:dd8ea6ebee7aedbf7c749fa80521d9ccf1ba473e0d1e14805caafbaad281c889"}, + {file = "markupsafe-3.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dff05cb7016dff1e9fd68f4122c127b65dfc59de5306cfb7ad92f956f230bee2"}, + {file = "markupsafe-3.0.4-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:cf63c214fe879a65e69a386f915e36104fc84254ab141240f8854602d8e0be2a"}, + {file = "markupsafe-3.0.4-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2a6ef68ae94aed8721934072b27a3b654ea2100b97e4ab864cf1489c90926fbc"}, + {file = "markupsafe-3.0.4-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:fd9f8797427910198f95bced71ddfed61130d7e349213bfb8466c9c99e2c46a8"}, + {file = "markupsafe-3.0.4-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d1aca03ede943eb80ab3d63bb082c84b7aab85ea83bd0fd0c200260945fb49d9"}, + {file = "markupsafe-3.0.4-cp310-cp310-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:0764a13d34cae40db7bbf3a09b7e9b491bf4603e20b263a7a9d6b8e324975d0a"}, + {file = "markupsafe-3.0.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9388003072b95f2f1e3fd908604194d653ba21330d811961a78b7da1a77e9e36"}, + {file = "markupsafe-3.0.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8698d70a8081ee8c090dbb394768b5789a1da8b131b5499f89d071dd3cfaf6be"}, + {file = "markupsafe-3.0.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:bf053da3c97a4bc5ecfbb218cdd2983febd91c617be8367d139882aa11e490aa"}, + {file = "markupsafe-3.0.4-cp310-cp310-musllinux_1_2_riscv64.whl", hash = "sha256:9438a2648b2195980cb2dd8e53ed7b8df91319e2d0b70ae61a9e1d1bc8d3bec9"}, + {file = "markupsafe-3.0.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:88d59b473bfb03259722600839af9bbd7fa13a2eb514beefeedb95997882f69a"}, + {file = "markupsafe-3.0.4-cp310-cp310-win32.whl", hash = "sha256:4a540e2d3192792fc84eced57bef37851ccb2b41f73291bb17408eea77bcd278"}, + {file = "markupsafe-3.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:5c22873ad1f0532ba40fa1727f3c0fc1bbbaab6d373d4cbe3f0dc74b2e2521c7"}, + {file = "markupsafe-3.0.4-cp310-cp310-win_arm64.whl", hash = "sha256:3d23795802fc8bd72534836d64489bbf0f67c088959091bdb22e10735a5107bf"}, + {file = "markupsafe-3.0.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9e25feb9e330b63edb0278a0acdf85e50d0cb0fbf49c3084abbe4e24ae195346"}, + {file = "markupsafe-3.0.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7d3391b2188d18737cb2fa147028b1096236eaa7e156446c650a489fa2cadc91"}, + {file = "markupsafe-3.0.4-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:849dd2bb0e5e4ab2b71c7191726a4a8d5aa8a610daa584728cbee0b710ddc4ef"}, + {file = "markupsafe-3.0.4-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:befb4158af32106b9a93db8d6d1d1cbbd418c0d5aca0cabb7b1780abf0c89169"}, + {file = "markupsafe-3.0.4-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:71f88e749ea29f67f21f3b36433c1dc54c7729ed2a6d9e2da2e0d9e0d7b224eb"}, + {file = "markupsafe-3.0.4-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6da83a088f8ef93b2d483a8232a4dbf4d69d3d8496b568a03c56becac43e1808"}, + {file = "markupsafe-3.0.4-cp311-cp311-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:8f0fac8b13d14bb06c68195f849371924ae53dd7b1c00fed24650f704383b692"}, + {file = "markupsafe-3.0.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:4a7cdc2a420ca01058182da4253329764d4bfa055564d1eced90e6ba1e8b1d3d"}, + {file = "markupsafe-3.0.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:83b3944fea42a8400edf92fd1770fb8d0d4f7de651353bd2d8525a92dba69a21"}, + {file = "markupsafe-3.0.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:8138eb83940ec7299024d92d4dee45f601b9e6c5ffde9d25f4e35e326203c707"}, + {file = "markupsafe-3.0.4-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:811d02d5122171c1941357efd8f9bf4ffe907b7f0a1a4e729a880e4be3f46e3e"}, + {file = "markupsafe-3.0.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:50b5bedc9ed8a94fc8857a42ef4f84a81ea88f8d4f05dc8705fb23ee6d8dcca7"}, + {file = "markupsafe-3.0.4-cp311-cp311-win32.whl", hash = "sha256:2e5a7cd7fdd14fcb1ae5d7d8bf23d24fbd1daefd1fbca2580132e1ea75f098b5"}, + {file = "markupsafe-3.0.4-cp311-cp311-win_amd64.whl", hash = "sha256:fdb4ca07ab75ffadab4a8b135ad59cdbb3156b99310f3d565370da74a15d6bd3"}, + {file = "markupsafe-3.0.4-cp311-cp311-win_arm64.whl", hash = "sha256:569d65055d367e3dcdf30c3f41119467b73d9ee9faf332bdf40402644f5ac08e"}, + {file = "markupsafe-3.0.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:61631e08084be9e21a8967ec3139c7616ed7c5e9368e05c86d1b39562c8a57b6"}, + {file = "markupsafe-3.0.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0930db9bdc62d22944e10b066448bb65dc9abe9112880c7cab8da54db4284d5f"}, + {file = "markupsafe-3.0.4-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6a45c3d514f2436064db00d7fc8778d888f0236ebfed649b53d13a59e69ad51b"}, + {file = "markupsafe-3.0.4-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1e1451fab512d1bcc3dc26988ec1edb0b82c2db909132872cd9356070a6b63df"}, + {file = "markupsafe-3.0.4-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:bd3ce56ae2cbae3ba82b683bc425cd7e48d2ed8b10f3e818186b6f5646d9271c"}, + {file = "markupsafe-3.0.4-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8e124f974786f831d6043728e38296969d3579db8896fe004682f5758e613581"}, + {file = "markupsafe-3.0.4-cp312-cp312-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:c02e8f18bdedba082cef725942ac823b9b60656db07f7e265cb31618dfd00d77"}, + {file = "markupsafe-3.0.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:9f098115c247e11d138ab83a28fa0323c77015007ea2df73ba5fd714dfefd67c"}, + {file = "markupsafe-3.0.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:d5f93ebbeb8032d47e349328ec8662d973d9b05a70b3c35df1f91fe419b84749"}, + {file = "markupsafe-3.0.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:64511c54db4e4987aef4c41923235927428729e8174c5dba488429be70a998ed"}, + {file = "markupsafe-3.0.4-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:e1a622f13970d81f95d0c72f9dc090dce9085fccfa4c9f2174377ee32bd15786"}, + {file = "markupsafe-3.0.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:c9a7f43c0b202b334cc9184af09bb8f21d3a209e038efaf106936fb69e6b026e"}, + {file = "markupsafe-3.0.4-cp312-cp312-win32.whl", hash = "sha256:f0ec3b750b59375eab5b0fb2b9254810c00a3375be6d789899f1055a1d556237"}, + {file = "markupsafe-3.0.4-cp312-cp312-win_amd64.whl", hash = "sha256:11935df9bf455ed0c04eb87bcd720f02b1fe5e02128a9430f23aed6f93336fc7"}, + {file = "markupsafe-3.0.4-cp312-cp312-win_arm64.whl", hash = "sha256:a4bbd2d87dd233b9fc5812160c3d0ffbe42edc22a26ce0469f58479ede633fe9"}, + {file = "markupsafe-3.0.4-cp313-cp313-android_24_arm64_v8a.whl", hash = "sha256:de8b364c423ef0a4bad9069657d617f9a5d2b2062457a89b1fa16ee199c399c1"}, + {file = "markupsafe-3.0.4-cp313-cp313-android_24_x86_64.whl", hash = "sha256:34bdde374c5932765d7dc685c4a1d191a3207852d67e8e0a9eb6ea85156181f1"}, + {file = "markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphoneos.whl", hash = "sha256:6bd9e1788e15bfcf6a9082de42e30387e7b85d211ab21e57a939bb8cfaaf8d96"}, + {file = "markupsafe-3.0.4-cp313-cp313-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:5066b244f576f91afc8ee3ba029a89f99d39c79b1853fe9d39bea9f0afbec148"}, + {file = "markupsafe-3.0.4-cp313-cp313-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:7a83aa6e4805df46fed18e989d3d16f86ef60cb50bbc8d9ce3a6be89165fbf6e"}, + {file = "markupsafe-3.0.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2d1b7d9308288661f56672b1b157d75fc536714d3638487bbea17b6318a78248"}, + {file = "markupsafe-3.0.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:73e77980c7207854f00fc4e71fb1626868d5740ab4012623d55c7a99ad122a72"}, + {file = "markupsafe-3.0.4-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7018d4af1cd272e847aa5917983ab5e83e4f6579f9dbfecd4a79c0ca80b144c2"}, + {file = "markupsafe-3.0.4-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c90d5b3d4e944e065a301d741b3c1d784f6bd1f503aa68b4967e32b2ba313d85"}, + {file = "markupsafe-3.0.4-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18a801868a884f216e784d7d14db2a4077143ce7610440aee2ce8f734e7cfcde"}, + {file = "markupsafe-3.0.4-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:434139499bb20b502ed3baa1f169e618f924a97e7a777fea1a49446d80106cf6"}, + {file = "markupsafe-3.0.4-cp313-cp313-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:9e227f3dbe6bde7491cf0a9965d00b88c6b1a4a95d11480ddf88bb96d397c19f"}, + {file = "markupsafe-3.0.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b8cd1f918b26fd7b1832ece557cc18f2d8747309ff8b3f0ef9d4250c5ad67a39"}, + {file = "markupsafe-3.0.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:a5fcffb37e602b0b3c1638a97746b9b96125caa9bcf6fa41d337a9261de231ee"}, + {file = "markupsafe-3.0.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:5989cb26b2e1efc6a42216a9f6b5ee495ce5ace2e5b352a9af489976b32d1ee2"}, + {file = "markupsafe-3.0.4-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:add96447a86d205ab616665d53b2950ee81083757f56e6ea833c8b2917646b46"}, + {file = "markupsafe-3.0.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2628d3a8cb648ecebb3c5d6b0a1052d400e4d8b7ac0fb786be8d285b50040d17"}, + {file = "markupsafe-3.0.4-cp313-cp313-win32.whl", hash = "sha256:672d207103e6b16ca098611b0f9efad6bc00afd47c03d6ef62186495ca677dc0"}, + {file = "markupsafe-3.0.4-cp313-cp313-win_amd64.whl", hash = "sha256:1f1f9477e174582b0a1b583d60b66e1f2cf5d3fe12cee985e4aedf44766600e5"}, + {file = "markupsafe-3.0.4-cp313-cp313-win_arm64.whl", hash = "sha256:06de8ef6331f6e822c28d577dc8bf43fe398800477c49498f38fc38b67ff33fc"}, + {file = "markupsafe-3.0.4-cp314-cp314-android_24_arm64_v8a.whl", hash = "sha256:4ed644d75aa94a2baf7ec3a96eaa160ea58c742eb9d27c6506053c5c40fc84ed"}, + {file = "markupsafe-3.0.4-cp314-cp314-android_24_x86_64.whl", hash = "sha256:6d2a9efe686f9de00d0d1ea32a4a5a86d558a2277501bd78d964214eab625e59"}, + {file = "markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphoneos.whl", hash = "sha256:8781a792a070cf2bd1b86d3aa943894115faaba6e88122a7bf32d62072742453"}, + {file = "markupsafe-3.0.4-cp314-cp314-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:971a3bbb75d97ae4e2e8f7d4834236f86f85f0c85e04ab2e191db1123b04f80b"}, + {file = "markupsafe-3.0.4-cp314-cp314-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:8909c2f1c6dd65e054ac4b573a91c8384d1492281e55d82d159d653f7a13adf6"}, + {file = "markupsafe-3.0.4-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:4cf3468d5ec187ffffcaca8e61929a37448f215dafc1386a12c750a72fe53634"}, + {file = "markupsafe-3.0.4-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:52704c5d36eb6dda8866493decd61111fff86244c9b1ad225ca01b9e91e5970f"}, + {file = "markupsafe-3.0.4-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1caa2fa5a6184fb233153b35f654e6687bd555476f6170f29d8ee9be1a8b0af9"}, + {file = "markupsafe-3.0.4-cp314-cp314-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:387d8cd30e69b3f0a72877b9ae717033396404e19095b17fe89753a981fda44f"}, + {file = "markupsafe-3.0.4-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:051417f74bcaaefa316276e0ff723f541616ca51043d070da00249d9bddd3e3c"}, + {file = "markupsafe-3.0.4-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:a8e9f292fcda89b324f2f5c91d13f1424a153e40fc2756f38ee23b15835ff300"}, + {file = "markupsafe-3.0.4-cp314-cp314-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:df1ae86ff54725a01fa1a0510b914ca53a161b7050be74f6204e24aded5971d0"}, + {file = "markupsafe-3.0.4-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:8965520ac587c94a4ac48b729be3d8b8de00af39699b17585dfb599babe77977"}, + {file = "markupsafe-3.0.4-cp314-cp314-musllinux_1_2_armv7l.whl", hash = "sha256:340cbb1957ba99929cbf19a75626d36ba1ae21d1730b287d1cf7f824a20c4fc7"}, + {file = "markupsafe-3.0.4-cp314-cp314-musllinux_1_2_ppc64le.whl", hash = "sha256:3a93d9616ddecfb393727a0041a562cf0b15a244e20f2bd25efc7949be4c4f17"}, + {file = "markupsafe-3.0.4-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:d2e56fd3b00222722abfb3f5f0759ddbae4b90811b5ad4343c64030ad1bde70c"}, + {file = "markupsafe-3.0.4-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:0d9c47709875fdb321452056622e930c52afbc07a7d780762fbb8b4d91ce6fa4"}, + {file = "markupsafe-3.0.4-cp314-cp314-win32.whl", hash = "sha256:38fc55594dab834470b6733dead2ee9e3f657fb0608c769dcafa0ba5ab52f45c"}, + {file = "markupsafe-3.0.4-cp314-cp314-win_amd64.whl", hash = "sha256:c1bc67752d5f21013cfe430df4062441714eab79f65a6a05e01505957e9c35fe"}, + {file = "markupsafe-3.0.4-cp314-cp314-win_arm64.whl", hash = "sha256:7e1636da3d8dfc220b6dd10264db5f2b165e4888c4518594898fbe381049af8a"}, + {file = "markupsafe-3.0.4-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:805c8b84534fa10891890f0e4be39f3a99e94615d93e8836bf9fa1fdca2feeb2"}, + {file = "markupsafe-3.0.4-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:fa95848c929b6a75f6848d3c9793e59db365ee436776e57db835cdbfa79ba977"}, + {file = "markupsafe-3.0.4-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e916035e3e9930cbdfdd10abf48861340221857f45509565898e012263f7b289"}, + {file = "markupsafe-3.0.4-cp314-cp314t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b4d12837e0203bbace818ff4a7461afdcd78bcd782351cea148139180d7bcffe"}, + {file = "markupsafe-3.0.4-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:5086f9975abb1ab531ee6afca1761e4b59a19b446f3f6522ed776963228cfe5a"}, + {file = "markupsafe-3.0.4-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:b4a635a0487774f841cb1fb62e907e7195cc95bc761e053184b8acc3ceb20733"}, + {file = "markupsafe-3.0.4-cp314-cp314t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:cb96e6e088d6cf71c1ea977510948320234824cf226e32f6f6e044f7a9c82b34"}, + {file = "markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:8b5d563170ff8ba3181caa967c99a3c804d1dedb702c7cb93a6a7c32247da978"}, + {file = "markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_armv7l.whl", hash = "sha256:396ec4e65cc889f69786b3b89478b471cee5a3bcf468b9d9bb03e1a30fb291fc"}, + {file = "markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_ppc64le.whl", hash = "sha256:15ba9e28640feef770374b116a6f019c21f52404aeabe516aa7f800587b98cfc"}, + {file = "markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:d920abdfa61279ba1a2ef9484aab07bf03331f8c08a10120fa332353d06e6932"}, + {file = "markupsafe-3.0.4-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:a9f54054101545a9a9cccefddf54316aa6e4491611fcbef9e91b3b6bebec04f6"}, + {file = "markupsafe-3.0.4-cp314-cp314t-win32.whl", hash = "sha256:12a606a492de952afcb43b59a14aaaaad120e708d3663dd0fdf2d738d427a691"}, + {file = "markupsafe-3.0.4-cp314-cp314t-win_amd64.whl", hash = "sha256:a18f38cafc329bac5e3c2b96c765b4c96d3d103421ed22ab7988c1e3fce27464"}, + {file = "markupsafe-3.0.4-cp314-cp314t-win_arm64.whl", hash = "sha256:eba154571c16e032112afac0dc2dfe9e63c2ceb7aedd07bb7eecf2ce26d4dd4c"}, + {file = "markupsafe-3.0.4-cp315-cp315-android_24_arm64_v8a.whl", hash = "sha256:737c9c3981998eba27f11786f84fddcbabc74068b72a4a1f454ea02094b57b65"}, + {file = "markupsafe-3.0.4-cp315-cp315-android_24_x86_64.whl", hash = "sha256:489505b03f692c3f376394e49194fa7a7f9e8558d6e293a7056a0032b0c38163"}, + {file = "markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphoneos.whl", hash = "sha256:077293e425f28ec737dbcad442a71752e28f8ae27cde3d68acd1fb212091cd92"}, + {file = "markupsafe-3.0.4-cp315-cp315-ios_13_0_arm64_iphonesimulator.whl", hash = "sha256:9348cbb300d224fe3b89793262cb093504d4ae927004468463f745188a193e4a"}, + {file = "markupsafe-3.0.4-cp315-cp315-ios_13_0_x86_64_iphonesimulator.whl", hash = "sha256:b807e598953730f82e4eae3bd30f6a122cf6b31c398c6b504c0e04c13c170429"}, + {file = "markupsafe-3.0.4-cp315-cp315-macosx_10_15_x86_64.whl", hash = "sha256:799c39bdf5e2f1292fedd3009f7b3c9e760f10b2420cb9638d56920840ff6db8"}, + {file = "markupsafe-3.0.4-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:ae9dcb8fbe244cb82f8a6458b455b927a03685e383d9bacf1ea5ce180b96dc97"}, + {file = "markupsafe-3.0.4-cp315-cp315-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4bced6e2a6dba6a28f7dd3c6ce14df1b2dd495923f16ea484cad03decd463b2b"}, + {file = "markupsafe-3.0.4-cp315-cp315-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:3882fb412298575bae3b9c46868251f15cc69307359f87bb1b382e53d6e5a2c9"}, + {file = "markupsafe-3.0.4-cp315-cp315-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:04e7902ba80ee4bac1d50a549606527a1dcf0476cd81403db41099d3b60ec653"}, + {file = "markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:925f929d6b59a8b3f8b8c6ac363cd0af7eecc81efb3071770b3c6717c450a369"}, + {file = "markupsafe-3.0.4-cp315-cp315-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f68edfc67aabac33708941f26f22a7b8e9f81429bc0cf249fcf7d66b23af8d19"}, + {file = "markupsafe-3.0.4-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:e5c802729725bd07e2bc3ab7b76dc7e0bbfc53129d8f1eb1c002c24cf774717e"}, + {file = "markupsafe-3.0.4-cp315-cp315-musllinux_1_2_armv7l.whl", hash = "sha256:55ffd6ce583d97dc71dc92e930324c8c0d25aea7e3ade6ae54ef77cedb096811"}, + {file = "markupsafe-3.0.4-cp315-cp315-musllinux_1_2_ppc64le.whl", hash = "sha256:2cb3dd71fc6be918ad4264346a8ed69485f9b7ed7bf35495d8e22807cd6b8bea"}, + {file = "markupsafe-3.0.4-cp315-cp315-musllinux_1_2_riscv64.whl", hash = "sha256:94f5407f7bc64fa6463906b896f9904beeeb7dd8dc116ee8e9056c8714ff9916"}, + {file = "markupsafe-3.0.4-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:2dad610540cb2e6272855c178f08ae9a1c7ac258a7fb71660553a5f104b42741"}, + {file = "markupsafe-3.0.4-cp315-cp315-win32.whl", hash = "sha256:03470d1a8268e692ecf79ecd565593e59d44219377a7ead61f1f1b94c1f7ff6b"}, + {file = "markupsafe-3.0.4-cp315-cp315-win_amd64.whl", hash = "sha256:d882a373d8093c2941e01291b7ced96e9cbe4781da9a7751ca7e6c70385e5214"}, + {file = "markupsafe-3.0.4-cp315-cp315-win_arm64.whl", hash = "sha256:353bd63081912ab8cfa6a0c7d185934cdf8426f04c618bba6bc4b394f2069b67"}, + {file = "markupsafe-3.0.4-cp315-cp315t-macosx_10_15_x86_64.whl", hash = "sha256:c61750fadcd119d0825bcb7d7d675dd264dcc89cc05292aab5be68ebdbb374ad"}, + {file = "markupsafe-3.0.4-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:1c0df495a977d10460a94941799c72d5b5ab03d3858d949b55b5a66c8f371c99"}, + {file = "markupsafe-3.0.4-cp315-cp315t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:02fa4acbc6a3fc5c693c34d4dd8c1130b7fe99cc915181b0ddd6f72aeb296002"}, + {file = "markupsafe-3.0.4-cp315-cp315t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:05295589e619b9bed252a86b532b8e27350abc372d18ba89b59375325e91ec1e"}, + {file = "markupsafe-3.0.4-cp315-cp315t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:be6cb0c799abb0e2ba3e618e6d28ddddf7e485f6c2ce938dfa237daf3905072c"}, + {file = "markupsafe-3.0.4-cp315-cp315t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:26e9867520db70d37f7fb421a7f0d8adb40171011fb84ce869afa1a83370dfa8"}, + {file = "markupsafe-3.0.4-cp315-cp315t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:f03460ff076f70ab595bb45a0205ccea1971443575b6920c52e755dec2b3fbfe"}, + {file = "markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:436e3ffc6310d3c41878c601db29098102fe5d8a467c49da4a4125254e0980f2"}, + {file = "markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_armv7l.whl", hash = "sha256:4e2c4809c14559aa7ef426f27fb35afbb38104c349a903bf8f3600456764bb38"}, + {file = "markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_ppc64le.whl", hash = "sha256:da2af0d7aebfc2074080d72efa6ab8317c62481ef1f896f65d9999c1c01f4494"}, + {file = "markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_riscv64.whl", hash = "sha256:aa2c838cc024642cc04c6854232f32b43e5e22833dd11119c1766c7873b8370d"}, + {file = "markupsafe-3.0.4-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:b91cc9d336957239ff200f30097e6fea2dc6d6fb3c81e853eaa09eac904fd894"}, + {file = "markupsafe-3.0.4-cp315-cp315t-win32.whl", hash = "sha256:e49fb0d1ce92cfa0cb198cc5b1b11cdf9d0638658e2a2db2687e39db7c87fc78"}, + {file = "markupsafe-3.0.4-cp315-cp315t-win_amd64.whl", hash = "sha256:4f6e0852a0283b1b1fd776eeb7b766a5f440b3e2bd31ab51af3b400585f3965c"}, + {file = "markupsafe-3.0.4-cp315-cp315t-win_arm64.whl", hash = "sha256:39dbacefc411633db5b4378b066a9aca70a3d7e2922c9e578d825f844026eeba"}, + {file = "markupsafe-3.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f291bcf42ae98eb5107edb162c3c998b4a89648fd8e99ed4cbd12705292788cd"}, + {file = "markupsafe-3.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ac0c7c9f1609b0c4c114feb1d7a3409564c7fb77e360bed9e97e5d25dfeaf868"}, + {file = "markupsafe-3.0.4-cp39-cp39-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:6768d67d1bce64270e0fdc2e69309d68b9b18ae56ddf6c711d168e9d051c2cac"}, + {file = "markupsafe-3.0.4-cp39-cp39-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:14bd2d845d62ab678eaf81da89d7b621b51756c72346745c1a594c09d49207a2"}, + {file = "markupsafe-3.0.4-cp39-cp39-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:007e1ffd9bf65bb6ee96df7b258fc632a4868dd5566037986c64781f35a36e98"}, + {file = "markupsafe-3.0.4-cp39-cp39-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:5e8b3d0b18fd623afa12ecb2ce8d8becef69f9b5440c6330c7972200e0bb84b0"}, + {file = "markupsafe-3.0.4-cp39-cp39-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:57f9947a7e57a081c1e3e0a2dd0d2dcf290a4531450e6f611e30084c222a7295"}, + {file = "markupsafe-3.0.4-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:b61687d0828e72bf5cda24a2690188f37170bd31c9359ac97e4e66569f120a16"}, + {file = "markupsafe-3.0.4-cp39-cp39-musllinux_1_2_armv7l.whl", hash = "sha256:0cee7cb0f9a1b6892ea482237d9403b3d1b4603aee057d0ff01f0fac2d019a97"}, + {file = "markupsafe-3.0.4-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:94e4c421742086aeee4c32a506eec8859d7634aad943f7e6aacf70f813478768"}, + {file = "markupsafe-3.0.4-cp39-cp39-musllinux_1_2_riscv64.whl", hash = "sha256:9240187afb63d2f9ddc3e032c670356fe941f6e20662ea168a5dc3f1f317e1b3"}, + {file = "markupsafe-3.0.4-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:e841068dc0be4cb6dfb5c890eb88cbdcff2f4a332393c7ec94e8e618bd32c1a8"}, + {file = "markupsafe-3.0.4-cp39-cp39-win32.whl", hash = "sha256:f61efe1d2fe0de16158a5fe1d1cf3c14bdb6aecd54d8938fd26512c525c1f624"}, + {file = "markupsafe-3.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:2b2b1e18af909b448bb3cf9e3433366f7a8726271fc214e8b10e0f62a78c724b"}, + {file = "markupsafe-3.0.4-cp39-cp39-win_arm64.whl", hash = "sha256:6669c1bf34080161ce49c589cc512ef24d4c704ac9d2b2d3667f519c60418378"}, + {file = "markupsafe-3.0.4.tar.gz", hash = "sha256:2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6"}, ] [[package]] @@ -1504,14 +1703,14 @@ files = [ [[package]] name = "moto" -version = "5.2.2" +version = "5.2.3" description = "A library that allows you to easily mock out tests based on AWS infrastructure" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "moto-5.2.2-py3-none-any.whl", hash = "sha256:3817f1e39721ca833579b921e53e3b68547ace6a34d848c9486fbb5905808de9"}, - {file = "moto-5.2.2.tar.gz", hash = "sha256:aac8023a429e125e91c91f8f4730a67b54f518cda587352f7e67252fe3168f75"}, + {file = "moto-5.2.3-py3-none-any.whl", hash = "sha256:5ec31b3cdbb383a19d46030157bd82aaaa7a9cc5f564200f995663d347bd4728"}, + {file = "moto-5.2.3.tar.gz", hash = "sha256:a9e95c3218b6eda18e74571f1ced11cb1bc3151467d562c1da6037b9d19832cb"}, ] [package.dependencies] @@ -1619,14 +1818,14 @@ reports = ["lxml"] [[package]] name = "mypy-boto3-s3" -version = "1.43.5" -description = "Type annotations for boto3 S3 1.43.5 service generated with mypy-boto3-builder 8.12.0" +version = "1.43.106" +description = "Type annotations for boto3 S3 1.43.106 service generated with mypy-boto3-builder 8.12.0" optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "mypy_boto3_s3-1.43.5-py3-none-any.whl", hash = "sha256:7cd836cf3ec384b6a05b108047034ece03bb7dd0bd0890c527673eafc44907bb"}, - {file = "mypy_boto3_s3-1.43.5.tar.gz", hash = "sha256:ba67dbc3da825b6818839db3823722f3b12304dd116e94ed398eb7ade86b0f62"}, + {file = "mypy_boto3_s3-1.43.106-py3-none-any.whl", hash = "sha256:e233d04dbcf3925522dff4346e75c37344ec3d1cbb82337e5eed2af263847668"}, + {file = "mypy_boto3_s3-1.43.106.tar.gz", hash = "sha256:731195f15830699a36e29d3c8abb2918bccd3587eb2edcb233f8046967893279"}, ] [[package]] @@ -1643,49 +1842,52 @@ files = [ [[package]] name = "networkx" -version = "3.6.1" +version = "3.7" description = "Python package for creating and manipulating graphs and networks" optional = false -python-versions = "!=3.14.1,>=3.11" +python-versions = "!=3.14.1,>=3.12" groups = ["main"] files = [ - {file = "networkx-3.6.1-py3-none-any.whl", hash = "sha256:d47fbf302e7d9cbbb9e2555a0d267983d2aa476bac30e90dfbe5669bd57f3762"}, - {file = "networkx-3.6.1.tar.gz", hash = "sha256:26b7c357accc0c8cde558ad486283728b65b6a95d85ee1cd66bafab4c8168509"}, + {file = "networkx-3.7-py3-none-any.whl", hash = "sha256:e3fd2c13a7814cee3746340d8d7f8598a67f16a58bf47fb7f8793fab6efca1b0"}, + {file = "networkx-3.7.tar.gz", hash = "sha256:fd77a511bd90f39f3d016351345b52cf5319b813bdca01de3f755d3cca62e96a"}, ] [package.extras] -benchmarking = ["asv", "virtualenv"] -default = ["matplotlib (>=3.8)", "numpy (>=1.25)", "pandas (>=2.0)", "scipy (>=1.11.2)"] +benchmarking = ["asv (>=0.6.5)", "py-rattler (>=0.21,<0.22)", "virtualenv"] +default = ["matplotlib (>=3.10)", "numpy (>=2.2)", "pandas (>=2.3)", "scipy (>=1.15)"] developer = ["mypy (>=1.15)", "pre-commit (>=4.1)"] doc = ["intersphinx-registry", "myst-nb (>=1.1)", "numpydoc (>=1.8.0)", "pillow (>=10)", "pydata-sphinx-theme (>=0.16)", "sphinx (>=8.0)", "sphinx-gallery (>=0.18)", "texext (>=0.6.7)"] -example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "igraph (>=0.11)", "iplotx (>=0.9.0)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.5)", "seaborn (>=0.13)"] -extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=1.14)", "sympy (>=1.10)"] +example = ["cairocffi (>=1.7)", "contextily (>=1.6)", "hiveplotlib (>=0.28)", "igraph (>=0.11)", "iplotx (>=0.9.0)", "momepy (>=0.7.2)", "osmnx (>=2.0.0)", "scikit-learn (>=1.6)", "seaborn (>=0.13)"] +extra = ["lxml (>=4.6)", "pydot (>=3.0.1)", "pygraphviz (>=2.0)", "sympy (>=1.10)"] release = ["build (>=0.10)", "changelist (==0.5)", "twine (>=4.0)", "wheel (>=0.40)"] test = ["pytest (>=7.2)", "pytest-cov (>=4.0)", "pytest-xdist (>=3.0)"] test-extras = ["pytest-mpl", "pytest-randomly"] [[package]] name = "nodeenv" -version = "1.10.0" +version = "1.11.0" description = "Node.js virtual environment builder" optional = false python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["dev"] files = [ - {file = "nodeenv-1.10.0-py2.py3-none-any.whl", hash = "sha256:5bb13e3eed2923615535339b3c620e76779af4cb4c6a90deccc9e36b274d3827"}, - {file = "nodeenv-1.10.0.tar.gz", hash = "sha256:996c191ad80897d076bdfba80a41994c2b47c68e224c542b48feba42ba00f8bb"}, + {file = "nodeenv-1.11.0-py2.py3-none-any.whl", hash = "sha256:edaa16e6c14d7cf395d75d4bbd5a26390f4dc06501a33b4e76282b02cc688a25"}, + {file = "nodeenv-1.11.0.tar.gz", hash = "sha256:3ce8fe5b71d16e8af7039ca65257354100bc772965d6bc549070649e53b1b146"}, ] +[package.extras] +certifi = ["certifi"] + [[package]] name = "oras" -version = "0.2.42" +version = "0.2.43" description = "OCI Registry as Storage Python SDK" optional = false python-versions = "*" groups = ["main"] files = [ - {file = "oras-0.2.42-py3-none-any.whl", hash = "sha256:d1e2184d42ce99258bd0ad56d932b0f4fce289bccf1b5094436a29579f385728"}, - {file = "oras-0.2.42.tar.gz", hash = "sha256:51d17088e5dffdeb585dd930bdccb4329762bef4af3f18600392ebae525a9231"}, + {file = "oras-0.2.43-py3-none-any.whl", hash = "sha256:bf295b1cfb5017f579c35c3394c7a71707f6aff463cb6699d5d191a6d8b56ea6"}, + {file = "oras-0.2.43.tar.gz", hash = "sha256:761f2b518fce50e5e9482975363ff0230f63fc65f84c09510fbcc301782a047c"}, ] [package.dependencies] @@ -1700,14 +1902,14 @@ tests = ["pytest (>=4.6.2)"] [[package]] name = "packaging" -version = "26.2" +version = "26.3" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev", "docs"] files = [ - {file = "packaging-26.2-py3-none-any.whl", hash = "sha256:5fc45236b9446107ff2415ce77c807cee2862cb6fac22b8a73826d0693b0980e"}, - {file = "packaging-26.2.tar.gz", hash = "sha256:ff452ff5a3e828ce110190feff1178bb1f2ea2281fa2075aadb987c2fb221661"}, + {file = "packaging-26.3-py3-none-any.whl", hash = "sha256:d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c"}, + {file = "packaging-26.3.tar.gz", hash = "sha256:94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79"}, ] [[package]] @@ -1729,14 +1931,14 @@ re2 = ["google-re2 (>=1.1)"] [[package]] name = "platformdirs" -version = "4.9.6" +version = "4.12.3" description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "platformdirs-4.9.6-py3-none-any.whl", hash = "sha256:e61adb1d5e5cb3441b4b7710bea7e4c12250ca49439228cc1021c00dcfac0917"}, - {file = "platformdirs-4.9.6.tar.gz", hash = "sha256:3bfa75b0ad0db84096ae777218481852c0ebc6c727b3168c1b9e0118e458cf0a"}, + {file = "platformdirs-4.12.3-py3-none-any.whl", hash = "sha256:080f3b39423b5abfca9a23d84c4e9795f54d395cd8459867a8ded44084fcd5f8"}, + {file = "platformdirs-4.12.3.tar.gz", hash = "sha256:427fc0bb321ae0c5b037fa03238ca74820437be162e78b4848c4d4055b9b766c"}, ] [[package]] @@ -1778,14 +1980,14 @@ test = ["coverage", "fixtures", "pytest", "requests-mock", "tox"] [[package]] name = "pre-commit" -version = "4.6.0" +version = "4.6.2" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "pre_commit-4.6.0-py2.py3-none-any.whl", hash = "sha256:e2cf246f7299edcabcf15f9b0571fdce06058527f0a06535068a86d38089f29b"}, - {file = "pre_commit-4.6.0.tar.gz", hash = "sha256:718d2208cef53fdc38206e40524a6d4d9576d103eb16f0fec11c875e7716e9d9"}, + {file = "pre_commit-4.6.2-py2.py3-none-any.whl", hash = "sha256:e2dde9a75d3bce11bd3831c26d134df00a2803c1d818be6a0383c3dcda25dc4e"}, + {file = "pre_commit-4.6.2.tar.gz", hash = "sha256:8f5d7bfb021ecdbcd9d49d89847082dd24172ccde534390081a679ad046e2441"}, ] [package.dependencies] @@ -1810,68 +2012,78 @@ markers = {main = "implementation_name != \"PyPy\"", dev = "platform_python_impl [[package]] name = "pygit2" -version = "1.19.3" +version = "1.20.1" description = "Python bindings for libgit2." optional = false python-versions = ">=3.11" groups = ["main"] files = [ - {file = "pygit2-1.19.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:59bca67a3f2af724659494bec9fed288b99242be13d76349d0170177512712fa"}, - {file = "pygit2-1.19.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb2e65666356f072d774f935aa0858f68ea34644d7a1467ea4918470748a2722"}, - {file = "pygit2-1.19.3-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0424822de48cb466f54c45c4d73924be201fd8ad347ccf0545fe7e601f056ebb"}, - {file = "pygit2-1.19.3-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e6aeb43e12fde33ec981209da90f66076e956538e457e4a50ba1665f97e3b2ea"}, - {file = "pygit2-1.19.3-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:eaf59b7f6435c276850d34392503b55e703392094ff4c87c3c0a4161b3d90133"}, - {file = "pygit2-1.19.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e536656457dd306d0ebae2ac442c2c8f8798ea2333095b85391bc3423f4ac1b3"}, - {file = "pygit2-1.19.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:38d52f8d30bf969e3bfcab22cf5cdc4dc69590e06e8e948b1bb25cccb3bbbe3d"}, - {file = "pygit2-1.19.3-cp311-cp311-win32.whl", hash = "sha256:8b7a0a16372b245d065efb10a4ef5d61dc08794a69fa8ed6dd1ff918409b7d84"}, - {file = "pygit2-1.19.3-cp311-cp311-win_amd64.whl", hash = "sha256:2b8f748836ac00fd785373ef8f5c9be1ed509e357cb270cc3f5674c0ad44d44d"}, - {file = "pygit2-1.19.3-cp311-cp311-win_arm64.whl", hash = "sha256:98f2241ef66ec97ab21a2a1a6851c1305929c7a9e9e3e94db5faeb5d2ed06aa2"}, - {file = "pygit2-1.19.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:d696ee240cc8b84e747b04443d85768c859ef0b88abe4a3505dc0b8e2a953ca0"}, - {file = "pygit2-1.19.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:86318a704bef836067fa9ac06c56591738d548dcdf2ea24ec227257e3f8115f8"}, - {file = "pygit2-1.19.3-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dc3ddb3e5d16cf662d2d0faeb53259e31ae584cc990cd76df909beeb4a36736a"}, - {file = "pygit2-1.19.3-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:73820fb34339fe3c52731d1c46c298a3239ee75b61bc3a2d9b45f8b8873acc47"}, - {file = "pygit2-1.19.3-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:20f6ad50608f51b053bf6c321ae2c31cc57f15e4131a4609261c44e29bdae7cb"}, - {file = "pygit2-1.19.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b2c63c7a371dbd5825e5fb7069b759c79aa5dec97806d49cb2c9f9a8a373209d"}, - {file = "pygit2-1.19.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:977eb52cd4134ff60d3faa168327a03f8724278c38bfcd347d8e3a11041ee9cd"}, - {file = "pygit2-1.19.3-cp312-cp312-win32.whl", hash = "sha256:14a2734d793d2d937d3bfc9d35b280ec83fc97a91b1934b1013554d41e6d3d70"}, - {file = "pygit2-1.19.3-cp312-cp312-win_amd64.whl", hash = "sha256:a7caeaf46aaa8e51c512af9ac1377f388e4836c9d042e134bbc5e22519fbd1bf"}, - {file = "pygit2-1.19.3-cp312-cp312-win_arm64.whl", hash = "sha256:2aafa010e3ac227913f398c8a680bce419e396dfe651685fffb779ed1c109a00"}, - {file = "pygit2-1.19.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9238bf7a8a953f4faedcbe90eb097b760a2709c7e7ab38edcf18dc2d0ce9dcff"}, - {file = "pygit2-1.19.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f999a4995504a6c14443de9481b7c6c54802663fe80c7504e1b946348f43786"}, - {file = "pygit2-1.19.3-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0918bc9b7597f243aa4b9c785912ae853e9aee4f572bcd5c9c591fcb703542f7"}, - {file = "pygit2-1.19.3-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:18403fee0171867be5fc1c1415bcd5d5a7fab51299bdd44bcf467c22a868fd22"}, - {file = "pygit2-1.19.3-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:cacece712337029092a98cf1af8d244e92fa8b36e5a64d7e14212ff73ea821e8"}, - {file = "pygit2-1.19.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:49d7c494bdaa5a8da366e4c4b7c822e52bd33bb6f22c67f8585b5396e91f8ac7"}, - {file = "pygit2-1.19.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:2bbe74fbe553c6f991512391822c27c9321e3a0b45cab872f45c8d458393eee3"}, - {file = "pygit2-1.19.3-cp313-cp313-win32.whl", hash = "sha256:3ab184751ca7a92007dbd8ae4ae4ac3b7228ef60ae2d2e18129b44bbe5c0aa4c"}, - {file = "pygit2-1.19.3-cp313-cp313-win_amd64.whl", hash = "sha256:522d9c6ab9206880dceaae5516720c0f0df706859d2ba97f49adcaeea2d661bd"}, - {file = "pygit2-1.19.3-cp313-cp313-win_arm64.whl", hash = "sha256:c77d5a1334ca3f1432c83457e03be8759d8e9040e0d25c59c738f2318545654a"}, - {file = "pygit2-1.19.3-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:214140f2201474e9d8e3889e5635e323aa90a58e6ae224a9de56be83d3e9b747"}, - {file = "pygit2-1.19.3-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:46fc9fd234b2a38176625af6bfd2dbad99ab937379a980761c59a343bdff4910"}, - {file = "pygit2-1.19.3-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eb9f46b561ee53f22cb479e7fdefd7b8ae478d12656436a48166c2ad81a3c021"}, - {file = "pygit2-1.19.3-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9f393932fadd8e74f26d7ebb58da649e7a188d9156b732dd6c9f0dfc273d4430"}, - {file = "pygit2-1.19.3-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:c9521a9b45de3affd82618e94f7e5116685e695e65fcbf67b2f1e44a086c0f4a"}, - {file = "pygit2-1.19.3-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:241f0fcd2aaf025e9fb5e1887eac5f244cb6b0a6e83dc27d673fa634ab0e0ee3"}, - {file = "pygit2-1.19.3-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:c1729caee68cdf35c0cdb913de3850724438e4bdf480742da4f21a3e86d83662"}, - {file = "pygit2-1.19.3-cp314-cp314-win32.whl", hash = "sha256:2c300d234ef15e4c557a7e9ac880163606b364d0d4e20ddbf1204b4ee9f9b61c"}, - {file = "pygit2-1.19.3-cp314-cp314-win_amd64.whl", hash = "sha256:0ff9f187b01d6629c14ad069b100e147093b70279496984faa012783c5832b66"}, - {file = "pygit2-1.19.3-cp314-cp314-win_arm64.whl", hash = "sha256:cdfbf879ee0d468d7929eb26e35db7442b56a411af1d5b7d28e858cccf71598a"}, - {file = "pygit2-1.19.3-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:79a3b565e20bbbbf21d29de1675a18e0e556545a2c738f38c0ac0435269f56bd"}, - {file = "pygit2-1.19.3-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:828856512070cda223c19046b02af50135a5b0efa274a80fbf7c82d773f8e89f"}, - {file = "pygit2-1.19.3-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:eec2b1d50bf52d2139d3d478d6d5f5ee56103da4a6dbd786344e8a85254dd07b"}, - {file = "pygit2-1.19.3-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbfa10f22670e7fef13bf249c32aebcafe23115790155d6b71efafb9aa7d4cba"}, - {file = "pygit2-1.19.3-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d22c2940bde27f9ffe095aac87e7c8b8a9c787f91782c7463387d39a2592d04c"}, - {file = "pygit2-1.19.3-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:0ed9f15b4b0b80191669fdf5b702b697ffbc245d24995befa80e46bef3aea25e"}, - {file = "pygit2-1.19.3-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:40f1253e042d0a5dfed16eec92b5b28a529c2873f4ee77ca60d1ea7b79a14600"}, - {file = "pygit2-1.19.3-cp314-cp314t-win32.whl", hash = "sha256:245d627a8ae3f35dafd9ce5b35538ddb5ba0c3fe6be8d2f9aa410f93a9184b83"}, - {file = "pygit2-1.19.3-cp314-cp314t-win_amd64.whl", hash = "sha256:8d2e3044ac1b09ef9120deb1896a56423c6dd17eb5ac4012c3c49dd590ee4910"}, - {file = "pygit2-1.19.3-cp314-cp314t-win_arm64.whl", hash = "sha256:ef2790c9ff7e7673d7262e9e059c5af86c09197037073fd004d22a63e4151291"}, - {file = "pygit2-1.19.3-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:7a1fe33a036aa2172934cafbdd17e2a0f3a73477727fc147e94f881bfe3961c2"}, - {file = "pygit2-1.19.3-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:09db53b92c546e621218fb82a97149dc7a155a8323a3dbce6b5048da70b0c00c"}, - {file = "pygit2-1.19.3-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c14d61de0c803188a0481d394a8ba61c7e1c38210a1e525097f18a0ad563009e"}, - {file = "pygit2-1.19.3-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:806d1e22d3828ea6767fb025f355374d6dd562161a0312f995723ab15e1de42d"}, - {file = "pygit2-1.19.3-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:5af3422728f61958b6a0faaf7de754ecae5bed689adc31d1b727da3c697a752b"}, - {file = "pygit2-1.19.3.tar.gz", hash = "sha256:a543e6d4ebb43825564935758dc234e770016fed673b84370d46ae9580558831"}, + {file = "pygit2-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:46664438cc9aadb342df445be15d96c4bea77544ac641ab79d2977dccd0f0948"}, + {file = "pygit2-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd18be3dcb5d0d1723f9294748f681d7206ad5e54202e862239f07f10e006803"}, + {file = "pygit2-1.20.1-cp311-cp311-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:daa99ea66858b50ad1f6eab699d9cfe3b8c2c43e17296a5c9af6c71fa8d96576"}, + {file = "pygit2-1.20.1-cp311-cp311-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:9eef7be5132651da77b6278330cde2b776f8503e1a7a9058c790b0cb62dfbb5e"}, + {file = "pygit2-1.20.1-cp311-cp311-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:6f6f393dd052e1f635ea9f6b7d825cd9c8cd1c9462f68a197eab086657c7cf65"}, + {file = "pygit2-1.20.1-cp311-cp311-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:ee44842ec283a6d0d382a9df17ae757c1c2f975fa2e39b37bceaa5e3528dca29"}, + {file = "pygit2-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:af88e5e152c35919fc18de2c588434919e491a387316e9232faa9c615aa88904"}, + {file = "pygit2-1.20.1-cp311-cp311-musllinux_1_2_riscv64.whl", hash = "sha256:da44497239265ff0bf6b706ca71578399254a954aa4d8eb780cfab075893419e"}, + {file = "pygit2-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e387b02ab5ef01f03ba84ac0a300c3b13cf427d9063dba0fb4a66a6cf23783e0"}, + {file = "pygit2-1.20.1-cp311-cp311-win32.whl", hash = "sha256:2b321fd4e29c4ce8b46108730ef3e145cd3b7de5fd118cac8cabcc5d9ae989f5"}, + {file = "pygit2-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:4c5d154468206cf617340e7c9e96b53fcfee0c180cd38834c1dcdc5b0d0be8af"}, + {file = "pygit2-1.20.1-cp311-cp311-win_arm64.whl", hash = "sha256:72a4b9efdb1bbeb97ba466ac1c02f2bf7ed1edffd96d02a146017228eac68191"}, + {file = "pygit2-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0a1353e1e0074bc79f506c60b63dd6b59ff60a1f21570cb9721ce73ac3b8262"}, + {file = "pygit2-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8537a48ab25338f38d5707e8d34d8817eb7cc492fe551ef0219980fe6f77cd8d"}, + {file = "pygit2-1.20.1-cp312-cp312-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f09a132454dbc97f80fb8155fe5d2cc40b1924827c42e8c741b9950af6a509ef"}, + {file = "pygit2-1.20.1-cp312-cp312-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:1d60a644d1280210f88e00ebe9929212eb74b0e32260c61c22c0d148fe8d0afd"}, + {file = "pygit2-1.20.1-cp312-cp312-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:39724d0d4f922058e1105c6a084f5c801eef6b7991033e6cb8d3efd174ef5338"}, + {file = "pygit2-1.20.1-cp312-cp312-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:befdb91f1d5f09981289d9785948a4f902cc3a961904bf9ae40010ef71fd51b4"}, + {file = "pygit2-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:f25df036a3ea4fcaa5051a1cc3adc1ed62e328a3a68b139ceb41b344882c6ea8"}, + {file = "pygit2-1.20.1-cp312-cp312-musllinux_1_2_riscv64.whl", hash = "sha256:009b2b5d2eb01f5da2d6dcdd51acf67478dcf953799c0d1f425b04e60f4fd3d8"}, + {file = "pygit2-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:579ab2893420983662bdd1a6870f889e03674fb9c9dc314075083b7f741d3bf5"}, + {file = "pygit2-1.20.1-cp312-cp312-win32.whl", hash = "sha256:532a63e6a6f2457465d1c1497a3dabc2676daf17d7c8d919246cfc99137e3e57"}, + {file = "pygit2-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:0bab03e4879ea55fd9c7b16c2d28d8023484c82e1d145fad67b1ac0efca596f2"}, + {file = "pygit2-1.20.1-cp312-cp312-win_arm64.whl", hash = "sha256:38e663e69224d02611c7293d9bd633a2237560d730db7c3d9fd3662a468105ef"}, + {file = "pygit2-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:21adc71ee1ac877b00118c21d5f20150c90443e04b60e4da7e9db8504aaf048b"}, + {file = "pygit2-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e60f5d8a01593d8d51c97325a7b6b5b1f644fccef1f54c1b0a6d47f11ab359c1"}, + {file = "pygit2-1.20.1-cp313-cp313-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:e958111749908c4f1989e33f3a98754eda56b3279e56bfab6d6fb513a7ea688c"}, + {file = "pygit2-1.20.1-cp313-cp313-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:96f45b908d3daaea084f2ed659b1227a1727691a5a980a9bec3e37541afc1f22"}, + {file = "pygit2-1.20.1-cp313-cp313-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:0f65c55b5217dd2cea0fefe287624bb9522266d984a06d1e87c1879cf6bd7585"}, + {file = "pygit2-1.20.1-cp313-cp313-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:7a1201c416db8e9ad572a389299c2db9df36d613676599f0984b78446db55437"}, + {file = "pygit2-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:083df8b7b113afe3ceabdf17be8e7e4156f2938e22d2b3d17c96965568eea1b7"}, + {file = "pygit2-1.20.1-cp313-cp313-musllinux_1_2_riscv64.whl", hash = "sha256:2e8a64a50f8ad839acbf069f2552046bcafb01ccbe632dcb64cb29417f870ed1"}, + {file = "pygit2-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:cb369a00ebb1eb513c5219d9975bbd7d6a0e9b551c5440299142a21354b7d121"}, + {file = "pygit2-1.20.1-cp313-cp313-win32.whl", hash = "sha256:2eef49c2d0f1aa089c60b92f2b20604e3f27991bd1ceb8a8a51fb13075ce8427"}, + {file = "pygit2-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:5e4d6e37db59712e3f2148c33464536faf32bc863d283d97ebd280632ed5f138"}, + {file = "pygit2-1.20.1-cp313-cp313-win_arm64.whl", hash = "sha256:fe108609d988fee5bab198f2ad2cbbe9b5eb08c64919c0f68fcdb7adf6d5f3f0"}, + {file = "pygit2-1.20.1-cp314-cp314-macosx_10_15_x86_64.whl", hash = "sha256:ceaa949c826975addc1cfb7d9b487714e9fded04cca9dcf9b7a844ae2da8657b"}, + {file = "pygit2-1.20.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:6c69da2cd18366c2b9827d9a9c7ebb9dc593fea5defbbc9b7704c8a6222a7d56"}, + {file = "pygit2-1.20.1-cp314-cp314-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:3d507bf62f5d447e382667411972921e0afe923e9567f3476a1f7b73db8bf49b"}, + {file = "pygit2-1.20.1-cp314-cp314-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:edc36d68a9fc632ba8cf54dc2823aa03bee966d2e787aaed35fff606996519c0"}, + {file = "pygit2-1.20.1-cp314-cp314-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:860c971fd53a9f14713a51b6343827b82d2b7dc7955e8c28c81ca3c90033b6a2"}, + {file = "pygit2-1.20.1-cp314-cp314-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:523a1571a55e4dbb33bd052ed72132ffe02e204fab5229b840ffadb9ec62e671"}, + {file = "pygit2-1.20.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e40c7221c781a5421405155f1664f216ee2611ee5bf377aa4d4df446f50950fb"}, + {file = "pygit2-1.20.1-cp314-cp314-musllinux_1_2_riscv64.whl", hash = "sha256:2759b548ee9c5812cc34660c02076aa4a92d9a0c75678fcbf7ca9def9120bd7a"}, + {file = "pygit2-1.20.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:4455105391f0ca6e35f5d340348ad98811de5a09f50fe832b6f44f8d97286f08"}, + {file = "pygit2-1.20.1-cp314-cp314-win32.whl", hash = "sha256:bec861767a185d281cbf71620ecfe92cb529cd8a9acf3fa18d0820accae9debc"}, + {file = "pygit2-1.20.1-cp314-cp314-win_amd64.whl", hash = "sha256:b6630a7a61dbd831b2731ac715257851325daa839a3d1251d27f968e33866a19"}, + {file = "pygit2-1.20.1-cp314-cp314-win_arm64.whl", hash = "sha256:e7b6704ba134bf6d91d161844771f8501b909adf8feb8a479d8f95477ea253ea"}, + {file = "pygit2-1.20.1-cp314-cp314t-macosx_10_15_x86_64.whl", hash = "sha256:befbfc4841e8018de7ffb364675449dbea847b95ddf4d5116da07ed9566551ba"}, + {file = "pygit2-1.20.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:1ecb9382e94a7cc55339c7dd0024c011746a400543f61e518736012effad4fb4"}, + {file = "pygit2-1.20.1-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:10f872e4b57f7172ae07fb7f0080f4681ccecf9e779a816a0c6e55a0f96921f9"}, + {file = "pygit2-1.20.1-cp314-cp314t-manylinux_2_26_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e8c8ba963914a9797548a44baa798614a93f222f8cd41ea2ca3cc1e91a911f88"}, + {file = "pygit2-1.20.1-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:9ebf99b3eae022e8d67141cd89f73ab408f93870a0a3a38f4372c5c7b107346e"}, + {file = "pygit2-1.20.1-cp314-cp314t-manylinux_2_38_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:b7261f02e88b1dde453f340534eca6d70116a952e2ee6949b0f061fbe75c01dc"}, + {file = "pygit2-1.20.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:ea9e46030542223016880664a12b6387be6da6f8177f90b4f96b6f26e2e59b23"}, + {file = "pygit2-1.20.1-cp314-cp314t-musllinux_1_2_riscv64.whl", hash = "sha256:b0daf388b21f71c3e5e52a1168911feef36e6a5eff32a0c1bf78e23ace1e2d1d"}, + {file = "pygit2-1.20.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6cb313dd02e71d2b79b512040ebc5ff15189043d00c550594e2df920ab51bea1"}, + {file = "pygit2-1.20.1-cp314-cp314t-win32.whl", hash = "sha256:0217a3432b7af85c2946126b9369a16d5b4b4e7a61207b825a3d680d757c8561"}, + {file = "pygit2-1.20.1-cp314-cp314t-win_amd64.whl", hash = "sha256:030b2d60b82ff29ab66b73ec76a6e15298019d0ea963f8882ea6b7cc1c48fe0e"}, + {file = "pygit2-1.20.1-cp314-cp314t-win_arm64.whl", hash = "sha256:57473456976183d2b74e4ad4804e515ed648ed5fafe2c901ef166bcbd386668f"}, + {file = "pygit2-1.20.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:bb1ec65b486c1f06bb51945d73cb785f91ee34cdcee85217ed277aa68c429fe5"}, + {file = "pygit2-1.20.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:b15a1c21f39a8e1fc3d09179d9ad435f8db9ad1a39ed54afe8c00f8b9b6fab2f"}, + {file = "pygit2-1.20.1-pp311-pypy311_pp73-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:0faa5da9a2ca5bd54b02157497588c46f1d2ca463868718922923f79b05191fa"}, + {file = "pygit2-1.20.1-pp311-pypy311_pp73-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:d4a1af34170d1f8a1d788c8611a7465a4a834baa7daa3d380b1ef4391726e23a"}, + {file = "pygit2-1.20.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:6477884c76a5197138bc2abd1a5e36b6d45a8cf836290fa06289adb48a641437"}, + {file = "pygit2-1.20.1.tar.gz", hash = "sha256:36dff84d237f2b8f18b0b146d6e7c3f99a7bce2da98cc4103a14387f53319f95"}, ] [package.dependencies] @@ -1879,14 +2091,14 @@ cffi = ">=2.0" [[package]] name = "pygithub" -version = "2.9.1" +version = "2.10.0" description = "Use the full Github API v3" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "pygithub-2.9.1-py3-none-any.whl", hash = "sha256:2ec78fca30092d51a42d76f4ddb02131b6f0c666a35dfdf364cf302cdda115b9"}, - {file = "pygithub-2.9.1.tar.gz", hash = "sha256:59771d7ff63d54d427be2e7d0dad2208dfffc2b0a045fec959263787739b611c"}, + {file = "pygithub-2.10.0-py3-none-any.whl", hash = "sha256:192ada2a76e4afc7d6b37e500c9bfeba1731e6506697445a5ba1c4af8bf0b924"}, + {file = "pygithub-2.10.0.tar.gz", hash = "sha256:90ff24ef1cd1bd57124c2a3869cafee9d7b066909129ecdaba2c2d1903bc118d"}, ] [package.dependencies] @@ -1898,14 +2110,14 @@ urllib3 = ">=1.26.0" [[package]] name = "pygments" -version = "2.20.0" +version = "2.21.0" description = "Pygments is a syntax highlighting package written in Python." optional = false python-versions = ">=3.9" groups = ["main", "dev", "docs"] files = [ - {file = "pygments-2.20.0-py3-none-any.whl", hash = "sha256:81a9e26dd42fd28a23a2d169d86d7ac03b46e2f8b59ed4698fb4785f946d0176"}, - {file = "pygments-2.20.0.tar.gz", hash = "sha256:6757cd03768053ff99f3039c1a36d6c0aa0b263438fcab17520b30a303a82b5f"}, + {file = "pygments-2.21.0-py3-none-any.whl", hash = "sha256:2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9"}, + {file = "pygments-2.21.0.tar.gz", hash = "sha256:610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c"}, ] [package.extras] @@ -1913,14 +2125,14 @@ windows-terminal = ["colorama (>=0.4.6)"] [[package]] name = "pyjwt" -version = "2.12.1" +version = "2.15.1" description = "JSON Web Token implementation in Python" optional = false python-versions = ">=3.9" groups = ["main"] files = [ - {file = "pyjwt-2.12.1-py3-none-any.whl", hash = "sha256:28ca37c070cad8ba8cd9790cd940535d40274d22f80ab87f3ac6a713e6e8454c"}, - {file = "pyjwt-2.12.1.tar.gz", hash = "sha256:c74a7a2adf861c04d002db713dd85f84beb242228e671280bf709d765b03672b"}, + {file = "pyjwt-2.15.1-py3-none-any.whl", hash = "sha256:42d59d631f7768a1028a64c7ff581a9bf7519804daf91fc5b6c56e30eec5e193"}, + {file = "pyjwt-2.15.1.tar.gz", hash = "sha256:4f259e80cdfb6b3fc18a7de51fd1ef9ec79652f25019bae68975ca2468a34df8"}, ] [package.dependencies] @@ -1928,9 +2140,6 @@ cryptography = {version = ">=3.4.0", optional = true, markers = "extra == \"cryp [package.extras] crypto = ["cryptography (>=3.4.0)"] -dev = ["coverage[toml] (==7.10.7)", "cryptography (>=3.4.0)", "pre-commit", "pytest (>=8.4.2,<9.0.0)", "sphinx", "sphinx-rtd-theme", "zope.interface"] -docs = ["sphinx", "sphinx-rtd-theme", "zope.interface"] -tests = ["coverage[toml] (==7.10.7)", "pytest (>=8.4.2,<9.0.0)"] [[package]] name = "pynacl" @@ -2033,34 +2242,29 @@ six = ">=1.5" [[package]] name = "python-discovery" -version = "1.3.1" +version = "1.6.1" description = "Python interpreter discovery" optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "python_discovery-1.3.1-py3-none-any.whl", hash = "sha256:ed188687ebb3b82c01a17cd5ac62fc94d9f6487a7f1a0f9dfe89753fec91039c"}, - {file = "python_discovery-1.3.1.tar.gz", hash = "sha256:62f6db28064c9613e7ca76cb3f00c38c839a07c31c00dfe7ed0986493d2150a6"}, + {file = "python_discovery-1.6.1-py3-none-any.whl", hash = "sha256:d43fcdef879fe795352bd13ccf8d185ba5a9f86f36cfcd00529f596e737442b3"}, + {file = "python_discovery-1.6.1.tar.gz", hash = "sha256:cf87d3627dfb4412437fdd5b13eae402607722998d21567993aedbc59b23c15e"}, ] [package.dependencies] filelock = ">=3.15.4" -platformdirs = ">=4.3.6,<5" - -[package.extras] -docs = ["furo (>=2025.12.19)", "sphinx (>=9.1)", "sphinx-autodoc-typehints (>=3.6.3)", "sphinxcontrib-mermaid (>=2)", "sphinxcontrib-towncrier (>=0.4)", "towncrier (>=25.8)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.5.4)", "pytest (>=8.3.5)", "pytest-mock (>=3.14)", "setuptools (>=75.1)"] [[package]] name = "python-dotenv" -version = "1.2.2" +version = "1.2.4" description = "Read key-value pairs from a .env file and set them as environment variables" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a"}, - {file = "python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3"}, + {file = "python_dotenv-1.2.4-py3-none-any.whl", hash = "sha256:42269a8a5b3fd54ffa6f3d84b18abed50064717576b4ecf03dc4a55d8aa04fdc"}, + {file = "python_dotenv-1.2.4.tar.gz", hash = "sha256:f0d53e69935a851c0dcc78f3ab7aaccd8cabef0b92382b576b824212902873c0"}, ] [package.extras] @@ -2207,14 +2411,14 @@ fixture = ["fixtures"] [[package]] name = "responses" -version = "0.26.0" +version = "0.26.3" description = "A utility library for mocking out the `requests` Python library." optional = false python-versions = ">=3.8" groups = ["dev"] files = [ - {file = "responses-0.26.0-py3-none-any.whl", hash = "sha256:03ec4409088cd5c66b71ecbbbd27fe2c58ddfad801c66203457b3e6a04868c37"}, - {file = "responses-0.26.0.tar.gz", hash = "sha256:c7f6923e6343ef3682816ba421c006626777893cb0d5e1434f674b649bac9eb4"}, + {file = "responses-0.26.3-py3-none-any.whl", hash = "sha256:74474f799334ac4f37d93b6437ecc3bb1bb5c77a8d31780a338643be2dce0af8"}, + {file = "responses-0.26.3.tar.gz", hash = "sha256:b0c11ca8131b8b227b8d5108e6ed39772222bd5aab030ed430e8f99057c4c409"}, ] [package.dependencies] @@ -2258,159 +2462,175 @@ files = [ [[package]] name = "rpds-py" -version = "0.30.0" +version = "2026.9.1" description = "Python bindings to Rust's persistent data structures (rpds)" optional = false -python-versions = ">=3.10" +python-versions = ">=3.11" groups = ["main"] files = [ - {file = "rpds_py-0.30.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:679ae98e00c0e8d68a7fda324e16b90fd5260945b45d3b824c892cec9eea3288"}, - {file = "rpds_py-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:4cc2206b76b4f576934f0ed374b10d7ca5f457858b157ca52064bdfc26b9fc00"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:389a2d49eded1896c3d48b0136ead37c48e221b391c052fba3f4055c367f60a6"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:32c8528634e1bf7121f3de08fa85b138f4e0dc47657866630611b03967f041d7"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f207f69853edd6f6700b86efb84999651baf3789e78a466431df1331608e5324"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:67b02ec25ba7a9e8fa74c63b6ca44cf5707f2fbfadae3ee8e7494297d56aa9df"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c0e95f6819a19965ff420f65578bacb0b00f251fefe2c8b23347c37174271f3"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_31_riscv64.whl", hash = "sha256:a452763cc5198f2f98898eb98f7569649fe5da666c2dc6b5ddb10fde5a574221"}, - {file = "rpds_py-0.30.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e0b65193a413ccc930671c55153a03ee57cecb49e6227204b04fae512eb657a7"}, - {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:858738e9c32147f78b3ac24dc0edb6610000e56dc0f700fd5f651d0a0f0eb9ff"}, - {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:da279aa314f00acbb803da1e76fa18666778e8a8f83484fba94526da5de2cba7"}, - {file = "rpds_py-0.30.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:7c64d38fb49b6cdeda16ab49e35fe0da2e1e9b34bc38bd78386530f218b37139"}, - {file = "rpds_py-0.30.0-cp310-cp310-win32.whl", hash = "sha256:6de2a32a1665b93233cde140ff8b3467bdb9e2af2b91079f0333a0974d12d464"}, - {file = "rpds_py-0.30.0-cp310-cp310-win_amd64.whl", hash = "sha256:1726859cd0de969f88dc8673bdd954185b9104e05806be64bcd87badbe313169"}, - {file = "rpds_py-0.30.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:a2bffea6a4ca9f01b3f8e548302470306689684e61602aa3d141e34da06cf425"}, - {file = "rpds_py-0.30.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:dc4f992dfe1e2bc3ebc7444f6c7051b4bc13cd8e33e43511e8ffd13bf407010d"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:422c3cb9856d80b09d30d2eb255d0754b23e090034e1deb4083f8004bd0761e4"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:07ae8a593e1c3c6b82ca3292efbe73c30b61332fd612e05abee07c79359f292f"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12f90dd7557b6bd57f40abe7747e81e0c0b119bef015ea7726e69fe550e394a4"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:99b47d6ad9a6da00bec6aabe5a6279ecd3c06a329d4aa4771034a21e335c3a97"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:33f559f3104504506a44bb666b93a33f5d33133765b0c216a5bf2f1e1503af89"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:946fe926af6e44f3697abbc305ea168c2c31d3e3ef1058cf68f379bf0335a78d"}, - {file = "rpds_py-0.30.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:495aeca4b93d465efde585977365187149e75383ad2684f81519f504f5c13038"}, - {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d9a0ca5da0386dee0655b4ccdf46119df60e0f10da268d04fe7cc87886872ba7"}, - {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8d6d1cc13664ec13c1b84241204ff3b12f9bb82464b8ad6e7a5d3486975c2eed"}, - {file = "rpds_py-0.30.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:3896fa1be39912cf0757753826bc8bdc8ca331a28a7c4ae46b7a21280b06bb85"}, - {file = "rpds_py-0.30.0-cp311-cp311-win32.whl", hash = "sha256:55f66022632205940f1827effeff17c4fa7ae1953d2b74a8581baaefb7d16f8c"}, - {file = "rpds_py-0.30.0-cp311-cp311-win_amd64.whl", hash = "sha256:a51033ff701fca756439d641c0ad09a41d9242fa69121c7d8769604a0a629825"}, - {file = "rpds_py-0.30.0-cp311-cp311-win_arm64.whl", hash = "sha256:47b0ef6231c58f506ef0b74d44e330405caa8428e770fec25329ed2cb971a229"}, - {file = "rpds_py-0.30.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a161f20d9a43006833cd7068375a94d035714d73a172b681d8881820600abfad"}, - {file = "rpds_py-0.30.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:6abc8880d9d036ecaafe709079969f56e876fcf107f7a8e9920ba6d5a3878d05"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca28829ae5f5d569bb62a79512c842a03a12576375d5ece7d2cadf8abe96ec28"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a1010ed9524c73b94d15919ca4d41d8780980e1765babf85f9a2f90d247153dd"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f8d1736cfb49381ba528cd5baa46f82fdc65c06e843dab24dd70b63d09121b3f"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d948b135c4693daff7bc2dcfc4ec57237a29bd37e60c2fabf5aff2bbacf3e2f1"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47f236970bccb2233267d89173d3ad2703cd36a0e2a6e92d0560d333871a3d23"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:2e6ecb5a5bcacf59c3f912155044479af1d0b6681280048b338b28e364aca1f6"}, - {file = "rpds_py-0.30.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a8fa71a2e078c527c3e9dc9fc5a98c9db40bcc8a92b4e8858e36d329f8684b51"}, - {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:73c67f2db7bc334e518d097c6d1e6fed021bbc9b7d678d6cc433478365d1d5f5"}, - {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5ba103fb455be00f3b1c2076c9d4264bfcb037c976167a6047ed82f23153f02e"}, - {file = "rpds_py-0.30.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:7cee9c752c0364588353e627da8a7e808a66873672bcb5f52890c33fd965b394"}, - {file = "rpds_py-0.30.0-cp312-cp312-win32.whl", hash = "sha256:1ab5b83dbcf55acc8b08fc62b796ef672c457b17dbd7820a11d6c52c06839bdf"}, - {file = "rpds_py-0.30.0-cp312-cp312-win_amd64.whl", hash = "sha256:a090322ca841abd453d43456ac34db46e8b05fd9b3b4ac0c78bcde8b089f959b"}, - {file = "rpds_py-0.30.0-cp312-cp312-win_arm64.whl", hash = "sha256:669b1805bd639dd2989b281be2cfd951c6121b65e729d9b843e9639ef1fd555e"}, - {file = "rpds_py-0.30.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:f83424d738204d9770830d35290ff3273fbb02b41f919870479fab14b9d303b2"}, - {file = "rpds_py-0.30.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e7536cd91353c5273434b4e003cbda89034d67e7710eab8761fd918ec6c69cf8"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2771c6c15973347f50fece41fc447c054b7ac2ae0502388ce3b6738cd366e3d4"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:0a59119fc6e3f460315fe9d08149f8102aa322299deaa5cab5b40092345c2136"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:76fec018282b4ead0364022e3c54b60bf368b9d926877957a8624b58419169b7"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:692bef75a5525db97318e8cd061542b5a79812d711ea03dbc1f6f8dbb0c5f0d2"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9027da1ce107104c50c81383cae773ef5c24d296dd11c99e2629dbd7967a20c6"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:9cf69cdda1f5968a30a359aba2f7f9aa648a9ce4b580d6826437f2b291cfc86e"}, - {file = "rpds_py-0.30.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a4796a717bf12b9da9d3ad002519a86063dcac8988b030e405704ef7d74d2d9d"}, - {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5d4c2aa7c50ad4728a094ebd5eb46c452e9cb7edbfdb18f9e1221f597a73e1e7"}, - {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ba81a9203d07805435eb06f536d95a266c21e5b2dfbf6517748ca40c98d19e31"}, - {file = "rpds_py-0.30.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:945dccface01af02675628334f7cf49c2af4c1c904748efc5cf7bbdf0b579f95"}, - {file = "rpds_py-0.30.0-cp313-cp313-win32.whl", hash = "sha256:b40fb160a2db369a194cb27943582b38f79fc4887291417685f3ad693c5a1d5d"}, - {file = "rpds_py-0.30.0-cp313-cp313-win_amd64.whl", hash = "sha256:806f36b1b605e2d6a72716f321f20036b9489d29c51c91f4dd29a3e3afb73b15"}, - {file = "rpds_py-0.30.0-cp313-cp313-win_arm64.whl", hash = "sha256:d96c2086587c7c30d44f31f42eae4eac89b60dabbac18c7669be3700f13c3ce1"}, - {file = "rpds_py-0.30.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:eb0b93f2e5c2189ee831ee43f156ed34e2a89a78a66b98cadad955972548be5a"}, - {file = "rpds_py-0.30.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:922e10f31f303c7c920da8981051ff6d8c1a56207dbdf330d9047f6d30b70e5e"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cdc62c8286ba9bf7f47befdcea13ea0e26bf294bda99758fd90535cbaf408000"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:47f9a91efc418b54fb8190a6b4aa7813a23fb79c51f4bb84e418f5476c38b8db"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1f3587eb9b17f3789ad50824084fa6f81921bbf9a795826570bda82cb3ed91f2"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:39c02563fc592411c2c61d26b6c5fe1e51eaa44a75aa2c8735ca88b0d9599daa"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:51a1234d8febafdfd33a42d97da7a43f5dcb120c1060e352a3fbc0c6d36e2083"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_31_riscv64.whl", hash = "sha256:eb2c4071ab598733724c08221091e8d80e89064cd472819285a9ab0f24bcedb9"}, - {file = "rpds_py-0.30.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6bdfdb946967d816e6adf9a3d8201bfad269c67efe6cefd7093ef959683c8de0"}, - {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c77afbd5f5250bf27bf516c7c4a016813eb2d3e116139aed0096940c5982da94"}, - {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:61046904275472a76c8c90c9ccee9013d70a6d0f73eecefd38c1ae7c39045a08"}, - {file = "rpds_py-0.30.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4c5f36a861bc4b7da6516dbdf302c55313afa09b81931e8280361a4f6c9a2d27"}, - {file = "rpds_py-0.30.0-cp313-cp313t-win32.whl", hash = "sha256:3d4a69de7a3e50ffc214ae16d79d8fbb0922972da0356dcf4d0fdca2878559c6"}, - {file = "rpds_py-0.30.0-cp313-cp313t-win_amd64.whl", hash = "sha256:f14fc5df50a716f7ece6a80b6c78bb35ea2ca47c499e422aa4463455dd96d56d"}, - {file = "rpds_py-0.30.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:68f19c879420aa08f61203801423f6cd5ac5f0ac4ac82a2368a9fcd6a9a075e0"}, - {file = "rpds_py-0.30.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:ec7c4490c672c1a0389d319b3a9cfcd098dcdc4783991553c332a15acf7249be"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f251c812357a3fed308d684a5079ddfb9d933860fc6de89f2b7ab00da481e65f"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ac98b175585ecf4c0348fd7b29c3864bda53b805c773cbf7bfdaffc8070c976f"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3e62880792319dbeb7eb866547f2e35973289e7d5696c6e295476448f5b63c87"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4e7fc54e0900ab35d041b0601431b0a0eb495f0851a0639b6ef90f7741b39a18"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47e77dc9822d3ad616c3d5759ea5631a75e5809d5a28707744ef79d7a1bcfcad"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:b4dc1a6ff022ff85ecafef7979a2c6eb423430e05f1165d6688234e62ba99a07"}, - {file = "rpds_py-0.30.0-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4559c972db3a360808309e06a74628b95eaccbf961c335c8fe0d590cf587456f"}, - {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:0ed177ed9bded28f8deb6ab40c183cd1192aa0de40c12f38be4d59cd33cb5c65"}, - {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:ad1fa8db769b76ea911cb4e10f049d80bf518c104f15b3edb2371cc65375c46f"}, - {file = "rpds_py-0.30.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:46e83c697b1f1c72b50e5ee5adb4353eef7406fb3f2043d64c33f20ad1c2fc53"}, - {file = "rpds_py-0.30.0-cp314-cp314-win32.whl", hash = "sha256:ee454b2a007d57363c2dfd5b6ca4a5d7e2c518938f8ed3b706e37e5d470801ed"}, - {file = "rpds_py-0.30.0-cp314-cp314-win_amd64.whl", hash = "sha256:95f0802447ac2d10bcc69f6dc28fe95fdf17940367b21d34e34c737870758950"}, - {file = "rpds_py-0.30.0-cp314-cp314-win_arm64.whl", hash = "sha256:613aa4771c99f03346e54c3f038e4cc574ac09a3ddfb0e8878487335e96dead6"}, - {file = "rpds_py-0.30.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:7e6ecfcb62edfd632e56983964e6884851786443739dbfe3582947e87274f7cb"}, - {file = "rpds_py-0.30.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a1d0bc22a7cdc173fedebb73ef81e07faef93692b8c1ad3733b67e31e1b6e1b8"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0d08f00679177226c4cb8c5265012eea897c8ca3b93f429e546600c971bcbae7"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5965af57d5848192c13534f90f9dd16464f3c37aaf166cc1da1cae1fd5a34898"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9a4e86e34e9ab6b667c27f3211ca48f73dba7cd3d90f8d5b11be56e5dbc3fb4e"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e5d3e6b26f2c785d65cc25ef1e5267ccbe1b069c5c21b8cc724efee290554419"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:626a7433c34566535b6e56a1b39a7b17ba961e97ce3b80ec62e6f1312c025551"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:acd7eb3f4471577b9b5a41baf02a978e8bdeb08b4b355273994f8b87032000a8"}, - {file = "rpds_py-0.30.0-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:fe5fa731a1fa8a0a56b0977413f8cacac1768dad38d16b3a296712709476fbd5"}, - {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:74a3243a411126362712ee1524dfc90c650a503502f135d54d1b352bd01f2404"}, - {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3e8eeb0544f2eb0d2581774be4c3410356eba189529a6b3e36bbbf9696175856"}, - {file = "rpds_py-0.30.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:dbd936cde57abfee19ab3213cf9c26be06d60750e60a8e4dd85d1ab12c8b1f40"}, - {file = "rpds_py-0.30.0-cp314-cp314t-win32.whl", hash = "sha256:dc824125c72246d924f7f796b4f63c1e9dc810c7d9e2355864b3c3a73d59ade0"}, - {file = "rpds_py-0.30.0-cp314-cp314t-win_amd64.whl", hash = "sha256:27f4b0e92de5bfbc6f86e43959e6edd1425c33b5e69aab0984a72047f2bcf1e3"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:c2262bdba0ad4fc6fb5545660673925c2d2a5d9e2e0fb603aad545427be0fc58"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:ee6af14263f25eedc3bb918a3c04245106a42dfd4f5c2285ea6f997b1fc3f89a"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3adbb8179ce342d235c31ab8ec511e66c73faa27a47e076ccc92421add53e2bb"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:250fa00e9543ac9b97ac258bd37367ff5256666122c2d0f2bc97577c60a1818c"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9854cf4f488b3d57b9aaeb105f06d78e5529d3145b1e4a41750167e8c213c6d3"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:993914b8e560023bc0a8bf742c5f303551992dcb85e247b1e5c7f4a7d145bda5"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58edca431fb9b29950807e301826586e5bbf24163677732429770a697ffe6738"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:dea5b552272a944763b34394d04577cf0f9bd013207bc32323b5a89a53cf9c2f"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ba3af48635eb83d03f6c9735dfb21785303e73d22ad03d489e88adae6eab8877"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:dff13836529b921e22f15cb099751209a60009731a68519630a24d61f0b1b30a"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:1b151685b23929ab7beec71080a8889d4d6d9fa9a983d213f07121205d48e2c4"}, - {file = "rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e"}, - {file = "rpds_py-0.30.0.tar.gz", hash = "sha256:dd8ff7cf90014af0c0f787eea34794ebf6415242ee1d6fa91eaba725cc441e84"}, + {file = "rpds_py-2026.9.1-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:2711d29b653b3bce48a63d18b9c6b53274669e6d6c4094dddeb4d9a0e45128b2"}, + {file = "rpds_py-2026.9.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3231c4c0e521dafa5be0c9f114ee2c2ad46650836f2d72caa86801950c3e7044"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e01b3c878c8641913e688edd1b3f08658c6783d29cf6b826bd3c0d1ae7a1ffaa"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3e524c7874ac72884d28e16dd5b8d839fd09e0fe76b020d3fbca23212a7b8c52"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:761fdae6728ceb99ab182fad2f0cc1e262f610834dc891aea1d1a2a2e634776f"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b723eb406dec5bc9ec516c73ab9c3239a3284e017f7eb89ee2b3258bd504fb7"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:136a1c3fe4402b7008bc81cb62ee538481795b61a7e83df88dff3b3f02b726ff"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_31_riscv64.whl", hash = "sha256:839dde845559254f34885267c6878f60d61d5205180226d976fe488d45fa128e"}, + {file = "rpds_py-2026.9.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:56cd8b3f77d7b6812f533b662186a1f28316931166ddc00fb893b1b0db7e9888"}, + {file = "rpds_py-2026.9.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:074a4d198bc34d9a8ea425114fc3ded6d11ec01f6a314a8db67454a5152d8834"}, + {file = "rpds_py-2026.9.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:6beb738155fe8ab8091afdfa5a3226b21c2b1593f1e50ebb90eb25b44dbc0391"}, + {file = "rpds_py-2026.9.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:57492a550a1d88d29d003247e5f78dd8cf04a701fac0e4c8db8745a6d2504e0a"}, + {file = "rpds_py-2026.9.1-cp311-cp311-win32.whl", hash = "sha256:d95a354e02393eada6d7351184671aced9d4cce109dabf927cb7aa99624352a1"}, + {file = "rpds_py-2026.9.1-cp311-cp311-win_amd64.whl", hash = "sha256:ce4d4f52e2a4324396caddbd45a97d8d7be5f42edd25d2355282a9c34f9b2f7f"}, + {file = "rpds_py-2026.9.1-cp311-cp311-win_arm64.whl", hash = "sha256:fdcd198979b4ecffcc1beba366a7fbcf4eb41243691a82fe52ceb0b902f09c12"}, + {file = "rpds_py-2026.9.1-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:50906f5aea24b5a865cbd0a589698288631d9f3a54c3a937c83aefa95a0d14af"}, + {file = "rpds_py-2026.9.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:e21c1429e205828ea886a2293a4a2c8e01f4c25d9893ca330e97a6cf73f52e7b"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2693b2728bbcc48d09a981a356954b0c47c53ff25b545856f28a889ea619f69a"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8601470267d938bcb7f3ab1a336100af51a4fd5b6ed030ef52461bb3ef5e7e07"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3890a6aa36e6baa53d5258a2a25d3ef8b37ad165a6ab27a892d7c3e3a432cd69"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:6b5b393eda5ea42cca1c1a6665f2a4882b4fd5d1777e41ce0545a107fb008c9d"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:addeda51556dac7c1a2f14cda62db8b621cd12afba3091d03a96c72932387eab"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_31_riscv64.whl", hash = "sha256:d9edf30457d74eebfd76b045535e36f1cd89062566a128a0db2145ca042d787e"}, + {file = "rpds_py-2026.9.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:815d26356930846a40c7bc1366e7b1b0320ab8a063e66c11298a208bed0fd237"}, + {file = "rpds_py-2026.9.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3b5a6f40f0a1486b4b36c888123afc67acdbd9f33235927acf5ff295429a0ba3"}, + {file = "rpds_py-2026.9.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5b8b0753718d258fd454283fbd57e14545d3b40583fa672e27cb4f987626bcc"}, + {file = "rpds_py-2026.9.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:46d80bc76b51a6c24f9944368c28d38b8bcbcea1da4f2f8d3ebc31a67e8c6ec6"}, + {file = "rpds_py-2026.9.1-cp312-cp312-win32.whl", hash = "sha256:befc2d6a953e563f8a7bfd87a42c22ebf8a3e980dcb7b6a4d17b70b0e914e8a3"}, + {file = "rpds_py-2026.9.1-cp312-cp312-win_amd64.whl", hash = "sha256:5ce8943f79c2210f7abcc28e86367b03b28d95027fd01c46d2472373ae70c86f"}, + {file = "rpds_py-2026.9.1-cp312-cp312-win_arm64.whl", hash = "sha256:501909f2e4a1e2dee528ef766fe3c469060ebc17e54a8383d404ba07a81a6f02"}, + {file = "rpds_py-2026.9.1-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:a36b70596407634ca82d4b989a3729074a008537a0522e4c8046a67c729103e9"}, + {file = "rpds_py-2026.9.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:eba5d173f7d5708b22a93815017a4611873ed54db9f268077c0dd1ed99cfc858"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:457866b85daf5034296666168b84a69e0b2e89dc4f1af102b46f6448a60b9063"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a3a52a3ba86436ab3aef510fbe21512abc2ddd1993005dfe50514bd2284ef025"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d7841166b7fa64c9c56404617ae4341448847482d45933b13135d26c130519e5"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:926bdd3e3b5998ddf70cc64bc8cf57209571f9044542913afb673799fec77dd0"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7868b85224291c6cb6759f9b5adb9745f486d226f62b16a614dd5a2a5ab2b35b"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_31_riscv64.whl", hash = "sha256:3cd182d7291d29b92c521a0069d9c01ba6193628a9a105531d11b40a6d731a33"}, + {file = "rpds_py-2026.9.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e6ea1cda8d8c688278430e4268a42f5e5da3bdd74578dfadc0820c3f1766ce83"}, + {file = "rpds_py-2026.9.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5943980471829f6de242a20b109de3111ba6b77e3af0ffc587028ac854b05e6c"}, + {file = "rpds_py-2026.9.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:76d3af9732d2dab69f28179b40ba2d87e2f1d5824b4a694780aa787d685e8f36"}, + {file = "rpds_py-2026.9.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:78326f4cb4427a56ba4996c0762b63be45f06b85f086526420d2b3a66e40f84d"}, + {file = "rpds_py-2026.9.1-cp313-cp313-win32.whl", hash = "sha256:172e47169583f46ce118cbec68e6795d0da0f4606b488b6434f8276bca0a058c"}, + {file = "rpds_py-2026.9.1-cp313-cp313-win_amd64.whl", hash = "sha256:3e93b2cd69a9830be33e03945cd7cda940a0a8bfcfbff41d6144f0cb0d3d8bd9"}, + {file = "rpds_py-2026.9.1-cp313-cp313-win_arm64.whl", hash = "sha256:d151e148117294133bf8af7eeace085e7e87432db15ab6adf640330298a47f6f"}, + {file = "rpds_py-2026.9.1-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:c9d1aca01f49170fdcf5c92761b1fafe97f554b721ca4570c5949fff778f0d4b"}, + {file = "rpds_py-2026.9.1-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:3f0e9ac28fc067d4d34b88ae43c48e9489455c97fee9633d851f7eeed5a05d35"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:07deecbfce94c78473018bc7d10b337cc651d12df87a1eb2cb3e4024bc9c33d0"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:821b2755db9194409254012f429c56643416fb96ef9be090be82ec8826b7f477"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3c91c210ae7645626c608400e3519b4a642f837cce09ca830db3beb2e9f274d4"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:54ac2158a6f96cfbabff0b2eedaf94b90c5ec7ca8317fcadc61e1c2b2e0ff6ef"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eac2f5dbafd585dfe31f86a23ebf0d3ba480a9d49ebc87947267b5608d4ea0cd"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_31_riscv64.whl", hash = "sha256:8aa5dda18d39b6143eb24809d158f9252c88f402749b6f1b62a506cc7d96cc35"}, + {file = "rpds_py-2026.9.1-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5c90e7fa02e8f5de0d10c17595c568ada48c5302e749462c0ea1a4c362111a86"}, + {file = "rpds_py-2026.9.1-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:e6d198bad4e49dd6732fbd636e2fc5c082f45c8cad0b4acb756b00c82c76072e"}, + {file = "rpds_py-2026.9.1-cp314-cp314-musllinux_1_2_i686.whl", hash = "sha256:96beca19ec79de272e8668585380ff9092c47077c1d7a1e098e00bbd921f4785"}, + {file = "rpds_py-2026.9.1-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:a5cf77eb04f20b720be95265a3e00eb2a14814074255cc27069c551b2db53118"}, + {file = "rpds_py-2026.9.1-cp314-cp314-win32.whl", hash = "sha256:a03d57b86d2a51d0a66c92177e2be154ad015f357791d306e714569999cdb4cc"}, + {file = "rpds_py-2026.9.1-cp314-cp314-win_amd64.whl", hash = "sha256:837c6b305e26fe0f75b15c92cf3b2ba29e0ae19dc40b1c557b026cb426347d0c"}, + {file = "rpds_py-2026.9.1-cp314-cp314-win_arm64.whl", hash = "sha256:fce4b85234a0cbad67bf8e6e1201ee815d172c9aebad75f25645bc4d834f8e31"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:3a72c11530d71abfb66c8d7696a2f86c43e63fca8b948f1a784ac490f4ec688e"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:068c37bba854ec2fe42f7365c640af11dd9895890ccbf2df5070d0c059bd7f96"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fca4eb6df565e2a928f1c7dad92d27db8f9df0f449e76423ed5d7e713ed445"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c933c6678c6f116ff8af47a4c6db0868b8ace74af0343016c0ef00f00272ea69"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:028ad274ea951dac64491b5d1e65712a4aeabfdbdb9fccf797b57bd899b0c495"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:740d0a99cf9de0b17a3943388e9294a59becf75e7c43421f387bd3c7a9901f7c"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0da298fb372dc192610a4b9ecbc68a0cd8b675bbbd1fc519d01b41cfd658333e"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_31_riscv64.whl", hash = "sha256:eb61be926bb81567c1f48bdc8aa22b9855048dc2efd53871f9f7e6e9a5632346"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:42e75466f83cd43f6026c81eab74246efb2bdadafb307b85700632d06c68f299"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:617f59cde379b4f648a09797b7f683d04b90a46344cddab85639da5aff0f5531"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-musllinux_1_2_i686.whl", hash = "sha256:3edae8c5ddfdb6985d49ae9d150516e5076888879022f91a26c2de9276ce0bdb"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:0f045bb053c9057720d72c56dffe30dffdc05997b2897a827b9325f0ab6623fa"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-win32.whl", hash = "sha256:bf35d0568abda97233239ce32896d3ad53fccc537832c104e30c94aa5fb93569"}, + {file = "rpds_py-2026.9.1-cp314-cp314t-win_amd64.whl", hash = "sha256:1e8d4d79d828299bf44a55db22a9388ab967b49d17132c88eab0f4360b48da8e"}, + {file = "rpds_py-2026.9.1-cp315-cp315-macosx_10_12_x86_64.whl", hash = "sha256:1d77b649e6f7cdf12ca5c2a98dad0ad37f9ea9b6f960408a92f0cb12bb3d04d9"}, + {file = "rpds_py-2026.9.1-cp315-cp315-macosx_11_0_arm64.whl", hash = "sha256:00ba2d8c7dd4ee537978ddf4b3fbd712bef2d8751603f7f3146b3f4287768e25"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ec450527cbf485e13c8d3602a54f428ab0432fdade0ede75efd74b735421c871"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:306ee1850d8105b5baf977e78d45fcadd12c1a54678d614c9baf217708446e91"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ef6b65b03247c54692ad4fd9ee97cb772781927db72e3cb05e70b3db6d1ff14f"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a575404ebc9cf2e91edd32eaf570ec1430eb900d4f56724ba7dd4bc1fc9c176d"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2c16ab111bc27c646ba8aa005d0527754edc538ebb636f0b1bf8e244b48d1945"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_31_riscv64.whl", hash = "sha256:7664419f27db41d4f1c43a78dccda7dd6e8ef2428df3ee01d0c2a07a6b071297"}, + {file = "rpds_py-2026.9.1-cp315-cp315-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:4b26b03d9d2658ee2fa234f8f4f19f38a09773fe5261028025032e26d4d35af0"}, + {file = "rpds_py-2026.9.1-cp315-cp315-musllinux_1_2_aarch64.whl", hash = "sha256:be3e47e2d91aa3942ff9bf4077a505226005abfc39b6f7554a91c1b9393986b9"}, + {file = "rpds_py-2026.9.1-cp315-cp315-musllinux_1_2_i686.whl", hash = "sha256:6307a0da524939decb8ca4a3933b8ab62525794411d6984fca6726e732804af6"}, + {file = "rpds_py-2026.9.1-cp315-cp315-musllinux_1_2_x86_64.whl", hash = "sha256:159a7aab5c5e8b112c8830f54717ce56da1252ebdbb526f5be2df2309280b9e7"}, + {file = "rpds_py-2026.9.1-cp315-cp315-win32.whl", hash = "sha256:dbc2673f9223d420c91145599b3ba45a8a50c207d1976908e5fb5ddb0c9b9429"}, + {file = "rpds_py-2026.9.1-cp315-cp315-win_amd64.whl", hash = "sha256:75c38c50ab9aca840225d9a9a3810bf11d04bd5c1f186cabbb8aee56db3e9b15"}, + {file = "rpds_py-2026.9.1-cp315-cp315-win_arm64.whl", hash = "sha256:a431156bb41865fc14cd5d79bb9d7bbed83110b0159e34e62ae30951f96c0009"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-macosx_10_12_x86_64.whl", hash = "sha256:ef0d8c843e2827d6c120ab4687e9423fb1d893db1df27b7c1506615bcb9734a0"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-macosx_11_0_arm64.whl", hash = "sha256:45bc6bccf78b20fd834237d18db64965d7ee68ba7f60440a26c7ab71e7b8d51a"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1d55198263bb51f557550c6ed2e6d1cb6a6fed6eb5c9120b741c5926bef8a45d"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8763f20692da7df39b0afdd1ba3042b004c50a45994f76c2d9a25641f7673db"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e43d4a1f673e8a1cbd8533e809e02b4bf9d4f2280269bb640436556312121250"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ea394a937f17a54c51239348bdbe2e3518124c8d4a8951ba04a311d3095bd18f"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdeaa99ce822dca76cfb1b993e9120c5ea212f2eb66d48950ad63c349668a018"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_31_riscv64.whl", hash = "sha256:b4f062343e7ad3fa94f2c66e5ae667dee47ee74dd41a9057c4fbe163236a123d"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:22ffd29a63d71fb1b81552c21f2c2b734949b7ac751a9be70675a939a900839b"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-musllinux_1_2_aarch64.whl", hash = "sha256:08dae4a4095150a7c4545a1fb40b98e1ab1744fbc2770d92c977b9dadaa49ab6"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-musllinux_1_2_i686.whl", hash = "sha256:9a0460d43603d1fd9ef59c30278531e15d78581721ddb538fa560aa7817ea4ad"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-musllinux_1_2_x86_64.whl", hash = "sha256:1c2d1f6da5128eabf34e963d7163a818846075a52568250d006c4c953b40f903"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-win32.whl", hash = "sha256:5c6ee90dee3e85e055ddfd502d611643d9b0fd94c818220bda84ec3dacd9b27b"}, + {file = "rpds_py-2026.9.1-cp315-cp315t-win_amd64.whl", hash = "sha256:fe5ad0664ec772b02c45859041aa17655709cced7a31005817fbbbd988c25567"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c0d2cb595a420b34d5086db0add011e26e2c09d6a024afbac4228bf8f863a30"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:f3d6ed6a98cfd19155996605474982cc470d7601746a6439078f1a5a3fa8b050"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8171b44a054e5c67fd748ada04187f1250bf35b95f85e52ab64bcf3331a923bb"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fda1d96e542c37b6c804547dbf489c129fe7c97183a76a5ec275909ba1a063df"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:270bdcdaac5d5b6f73c5e22e7e135c7f2a50e789f71d9e241d5be8d90026e19a"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:84a6ecc0c940169190d2c23bd969debd48c94dbc855acd60188a68d71d421608"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:ab4b2fda7c2b542f7f9d886cc6a838c5079d2b76f72e6081411faba11adde2c9"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:44b32a7c4f0da3d28af31c259e38ddcff096f855e205ed0671d02fcf44f1ea1c"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:a3dbc5ed9514908d5046107d7b1346bde71eea61de6e0e4919c19354f97e769f"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6eae33003518fd4cb4f83a218d5371469dd3001aa3b87128c005b07762f7fe5e"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp80-macosx_10_12_x86_64.whl", hash = "sha256:0483515261947e4e8b8e1375bf7463e7eb6ccfb3d86e7b554d90cd5285f20f32"}, + {file = "rpds_py-2026.9.1-pp311-pypy311_pp80-macosx_11_0_arm64.whl", hash = "sha256:4cfaf02209061880210819934de2f4f6aa83dc04dafe6770276acc240a56da31"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6cdc537c8633d7fd92a82e2e0d2ab74320a3f63d5e59fb9cf08711e08fe151c4"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:10e208f2425d973938afcd56e28a7c4be32e27b6a60b5d381f49fb9d8acf9759"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c0dbbcc19735fe5f8b0a54c07659d154a9e69f47e15d0a6ab7299215daf62cb"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:684fd492fff4fead00587544e059be2bbcb6f93454f21fa2a91b66fc7508be82"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1028417bb44037eb3069c1009bd7b7277212876cda22fbe565b0bca9fab6d2c"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_31_riscv64.whl", hash = "sha256:492e5e428cbe126221611f47e068f01660352feec4ad18bc0f5ea9b2ae88fb14"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:88b5268892fde430d5531f95bc560b6efbbd67c929662c586afd729a96e7461c"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:01445c8d194aa032a08e944f16567672da1c62dbdbefd8b6d0693032e290cf68"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-musllinux_1_2_i686.whl", hash = "sha256:eef6a03b0b6d08d0835ccfa8ec8d1bc70525e3801387567137b50c557695e6da"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:6b9bf3135b4ad5981df9a73d71a35272d650a2985ae9c2746357b24d59de2448"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp80-macosx_10_12_x86_64.whl", hash = "sha256:56c6952a9b15047466d0c2347c446a761d4527f89976156341e68f0ce5cc08b0"}, + {file = "rpds_py-2026.9.1-pp312-pypy312_pp80-macosx_11_0_arm64.whl", hash = "sha256:b242c27c8f836305a4a72df9cdd564386ac57b807bd252a063223331c9316b37"}, + {file = "rpds_py-2026.9.1.tar.gz", hash = "sha256:4793ef7f78268b124b73fa933440f01d258bbae01de9fa53e9080c9ab0425a12"}, ] [[package]] name = "s3transfer" -version = "0.19.0" +version = "0.19.2" description = "An Amazon S3 Transfer Manager" optional = false python-versions = ">=3.10" groups = ["main", "dev"] files = [ - {file = "s3transfer-0.19.0-py3-none-any.whl", hash = "sha256:777cc2415536f1debadb5c2ef7779275d0fc0fe0e042411cdd6caebeb2685262"}, - {file = "s3transfer-0.19.0.tar.gz", hash = "sha256:ce436931687addc4c1712d52d40b32f53e88315723f107ffa20ba82b05a0f685"}, + {file = "s3transfer-0.19.2-py3-none-any.whl", hash = "sha256:d8168eccca828cbb2cd573675333f3bddd254313a9c42494b84c76b539e8ba25"}, + {file = "s3transfer-0.19.2.tar.gz", hash = "sha256:ba0309fd86be3c27dbf78cdd813c13c5e1df16e5874b99d2535ebbdfb9892993"}, ] [package.dependencies] -botocore = ">=1.37.4,<2.0a0" +botocore = ">=1.37.4,<2.0a.0" [package.extras] -crt = ["botocore[crt] (>=1.37.4,<2.0a0)"] +crt = ["botocore[crt] (>=1.37.4,<2.0a.0)"] [[package]] name = "semver" -version = "3.0.4" +version = "3.1.0" description = "Python helper for Semantic Versioning (https://semver.org)" optional = false -python-versions = ">=3.7" +python-versions = ">=3.10" groups = ["main"] files = [ - {file = "semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746"}, - {file = "semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"}, + {file = "semver-3.1.0-py3-none-any.whl", hash = "sha256:6e4998f8b4762acdfea85f9bfd5b4032e0bb50038dc04bf82011b42d5d1145c5"}, + {file = "semver-3.1.0.tar.gz", hash = "sha256:14bc073439513d7773662a338f4db9829cf16c12b74b9568e2d2689975fbd7fc"}, ] +[package.extras] +native = ["fast-semver-rs-backend (>=0.1.1) ; platform_python_implementation == \"CPython\""] + [[package]] name = "six" version = "1.17.0" @@ -2425,14 +2645,14 @@ files = [ [[package]] name = "snowballstemmer" -version = "3.0.1" -description = "This package provides 32 stemmers for 30 languages generated from Snowball algorithms." +version = "3.1.1" +description = "This package provides 36 stemmers for 34 languages generated from Snowball algorithms." optional = false -python-versions = "!=3.0.*,!=3.1.*,!=3.2.*" +python-versions = ">=3.3" groups = ["docs"] files = [ - {file = "snowballstemmer-3.0.1-py3-none-any.whl", hash = "sha256:6cd7b3897da8d6c9ffb968a6781fa6532dce9c3618a4b127d920dab764a19064"}, - {file = "snowballstemmer-3.0.1.tar.gz", hash = "sha256:6d5eeeec8e9f84d4d56b847692bacf79bc2c8e90c7f80ca4444ff8b6f2e52895"}, + {file = "snowballstemmer-3.1.1-py3-none-any.whl", hash = "sha256:7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752"}, + {file = "snowballstemmer-3.1.1.tar.gz", hash = "sha256:e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260"}, ] [[package]] @@ -2466,37 +2686,16 @@ sphinxcontrib-jsmath = ">=1.0.1" sphinxcontrib-qthelp = ">=1.0.6" sphinxcontrib-serializinghtml = ">=1.1.9" -[[package]] -name = "sphinx-click" -version = "6.2.0" -description = "Sphinx extension that automatically documents click applications" -optional = false -python-versions = ">=3.10" -groups = ["docs"] -files = [ - {file = "sphinx_click-6.2.0-py3-none-any.whl", hash = "sha256:1fb1851cb4f2c286d43cbcd57f55db6ef5a8d208bfc3370f19adde232e5803d7"}, - {file = "sphinx_click-6.2.0.tar.gz", hash = "sha256:fc78b4154a4e5159462e36de55b8643747da6cda86b3b52a8bb62289e603776c"}, -] - -[package.dependencies] -click = ">=8.0" -docutils = "*" -sphinx = ">=4.0" - -[package.extras] -docs = ["reno"] -test = ["pytest", "pytest-cov"] - [[package]] name = "sphinx-markdown-builder" -version = "0.6.10" +version = "0.6.11" description = "A Sphinx extension to add markdown generation support." optional = false python-versions = ">=3.7" groups = ["docs"] files = [ - {file = "sphinx_markdown_builder-0.6.10-py3-none-any.whl", hash = "sha256:16d86738b9ac69fcbc86e373c31c6402c30af1fa8d98d0f62cc5f38bfe5fc26e"}, - {file = "sphinx_markdown_builder-0.6.10.tar.gz", hash = "sha256:cd5acf88d52ea0146a712fd557404f10326dff3428a78ba928e59b1727fd4a86"}, + {file = "sphinx_markdown_builder-0.6.11-py3-none-any.whl", hash = "sha256:acfb94d6ee66c7a47da0ca0420578fa16f115812af25b8fd21755d5909aacf51"}, + {file = "sphinx_markdown_builder-0.6.11.tar.gz", hash = "sha256:ba3bf33e0e42ff30ae686ac73957a95e6d045790dcfbaca012dd8ae01794e577"}, ] [package.dependencies] @@ -2659,14 +2858,14 @@ test = ["pytest"] [[package]] name = "stevedore" -version = "5.8.0" +version = "5.9.1" description = "Manage dynamic plugins for Python applications" optional = false -python-versions = ">=3.10" +python-versions = ">=3.11" groups = ["dev"] files = [ - {file = "stevedore-5.8.0-py3-none-any.whl", hash = "sha256:88eede9e66ca80e34085b9174e2327da2c61ac91f24f70e41c3ad76e4bb4872b"}, - {file = "stevedore-5.8.0.tar.gz", hash = "sha256:b49867b32ca3016e94100e68dbf26e72aa7b8708d0a3f73c08aeb220370ac715"}, + {file = "stevedore-5.9.1-py3-none-any.whl", hash = "sha256:5c8ff3a9f336cc1a06ac0f597bc79d11a2f950bfd32e290ca56b5a301fafafbf"}, + {file = "stevedore-5.9.1.tar.gz", hash = "sha256:e97a2667923efda926e8713fde6a73616df68210a3cbc6f02b48967b676fd8bf"}, ] [[package]] @@ -2684,52 +2883,28 @@ files = [ [package.extras] widechars = ["wcwidth"] -[[package]] -name = "types-awscrt" -version = "0.31.3" -description = "Type annotations and code completion for awscrt" -optional = false -python-versions = ">=3.8" -groups = ["dev"] -files = [ - {file = "types_awscrt-0.31.3-py3-none-any.whl", hash = "sha256:e5ce65a00a2ab4f35eacc1e3d700d792338d56e4823ee7b4dbe017f94cfc4458"}, - {file = "types_awscrt-0.31.3.tar.gz", hash = "sha256:09d3eaf00231e0f47e101bd9867e430873bc57040050e2a3bd8305cb4fc30865"}, -] - -[[package]] -name = "types-click" -version = "7.1.8" -description = "Typing stubs for click" -optional = false -python-versions = "*" -groups = ["dev"] -files = [ - {file = "types-click-7.1.8.tar.gz", hash = "sha256:b6604968be6401dc516311ca50708a0a28baa7a0cb840efd7412f0dbbff4e092"}, - {file = "types_click-7.1.8-py3-none-any.whl", hash = "sha256:8cb030a669e2e927461be9827375f83c16b8178c365852c060a34e24871e7e81"}, -] - [[package]] name = "types-pyyaml" -version = "6.0.12.20260518" +version = "6.0.12.20260906" description = "Typing stubs for PyYAML" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "types_pyyaml-6.0.12.20260518-py3-none-any.whl", hash = "sha256:d2150f75a231c9fe9c7463bd29487d93e60bac90400287351384bc2284eba7cd"}, - {file = "types_pyyaml-6.0.12.20260518.tar.gz", hash = "sha256:d917f83fb38462550338c1297faedd860b3ec83912b96b1e3d73255f7473e466"}, + {file = "types_pyyaml-6.0.12.20260906-py3-none-any.whl", hash = "sha256:bca893ff0d51df5c9053137d5d0e6ccd36e939a196356f1d5c16372422f5137b"}, + {file = "types_pyyaml-6.0.12.20260906.tar.gz", hash = "sha256:f59c1cc05010b833d2d72287bbaa72610106b28d42d89a907313117faba85212"}, ] [[package]] name = "types-requests" -version = "2.33.0.20260518" +version = "2.33.0.20260906" description = "Typing stubs for requests" optional = false python-versions = ">=3.10" groups = ["dev"] files = [ - {file = "types_requests-2.33.0.20260518-py3-none-any.whl", hash = "sha256:626d697d1adaaff76e2044dc8c5c051d8f21abc157bdfe204a75558076fe0bf0"}, - {file = "types_requests-2.33.0.20260518.tar.gz", hash = "sha256:df7bd3bfe0ca8402dfb841e7d9be714bb5578203283d66d7dc4ef69343449a5e"}, + {file = "types_requests-2.33.0.20260906-py3-none-any.whl", hash = "sha256:9f53622652bd921ead7a54d665be1b8d518165c8b51cc9d68d944cd6b6bfa8fb"}, + {file = "types_requests-2.33.0.20260906.tar.gz", hash = "sha256:76ab8a0fb736744a0c3deee7aa57b2927e301f078d9e61f5391b3e92002416b9"}, ] [package.dependencies] @@ -2749,26 +2924,26 @@ files = [ [[package]] name = "typing-extensions" -version = "4.15.0" +version = "4.16.0" description = "Backported and Experimental Type Hints for Python 3.9+" optional = false python-versions = ">=3.9" groups = ["main", "dev"] files = [ - {file = "typing_extensions-4.15.0-py3-none-any.whl", hash = "sha256:f0fa19c6845758ab08074a0cfa8b7aecb71c999ca73d62883bc25cc018c4e548"}, - {file = "typing_extensions-4.15.0.tar.gz", hash = "sha256:0cea48d173cc12fa28ecabc3b837ea3cf6f38c6d1136f85cbaaf598984861466"}, + {file = "typing_extensions-4.16.0-py3-none-any.whl", hash = "sha256:481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8"}, + {file = "typing_extensions-4.16.0.tar.gz", hash = "sha256:dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5"}, ] [[package]] name = "urllib3" -version = "2.7.0" +version = "2.8.0" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.10" groups = ["main", "dev", "docs"] files = [ - {file = "urllib3-2.7.0-py3-none-any.whl", hash = "sha256:9fb4c81ebbb1ce9531cce37674bbc6f1360472bc18ca9a553ede278ef7276897"}, - {file = "urllib3-2.7.0.tar.gz", hash = "sha256:231e0ec3b63ceb14667c67be60f2f2c40a518cb38b03af60abc813da26505f4c"}, + {file = "urllib3-2.8.0-py3-none-any.whl", hash = "sha256:0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3"}, + {file = "urllib3-2.8.0.tar.gz", hash = "sha256:63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63"}, ] [package.extras] @@ -2779,32 +2954,33 @@ zstd = ["backports-zstd (>=1.0.0) ; python_version < \"3.14\""] [[package]] name = "virtualenv" -version = "21.3.3" +version = "21.14.5" description = "Virtual Python Environment builder" optional = false -python-versions = ">=3.8" +python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "virtualenv-21.3.3-py3-none-any.whl", hash = "sha256:7d5987d8369e098e41406efb780a3d4ca79280097293899e351a6407ee153ab3"}, - {file = "virtualenv-21.3.3.tar.gz", hash = "sha256:f5bda277e553b1c2b3c1a8debfc30496e1288cc93ce6b7b71b3280047e317328"}, + {file = "virtualenv-21.14.5-py3-none-any.whl", hash = "sha256:b0651e0174982bba17cc6f0aaa2ef496730cb85a3f35eb5d1119d1c904f7d1da"}, + {file = "virtualenv-21.14.5.tar.gz", hash = "sha256:c4cb6c13e46b57225a999c7e22a09b163393878facc7ac4c059a57f46faa1647"}, ] [package.dependencies] distlib = ">=0.3.7,<1" -filelock = {version = ">=3.24.2,<4", markers = "python_version >= \"3.10\""} +filelock = {version = ">=3.24.2,<5", markers = "python_version >= \"3.10\""} +packaging = ">=23.1" platformdirs = ">=3.9.1,<5" -python-discovery = ">=1.3.1" +python-discovery = ">=1.6" [[package]] name = "werkzeug" -version = "3.1.8" +version = "3.1.9" description = "The comprehensive WSGI web application library." optional = false python-versions = ">=3.9" groups = ["dev"] files = [ - {file = "werkzeug-3.1.8-py3-none-any.whl", hash = "sha256:63a77fb8892bf28ebc3178683445222aa500e48ebad5ec77b0ad80f8726b1f50"}, - {file = "werkzeug-3.1.8.tar.gz", hash = "sha256:9bad61a4268dac112f1c5cd4630a56ede601b6ed420300677a869083d70a4c44"}, + {file = "werkzeug-3.1.9-py3-none-any.whl", hash = "sha256:6392e50c78460ba618e5b21f08a71f59c99ce99cdc6cf6e3dd7e6ccca8754fab"}, + {file = "werkzeug-3.1.9.tar.gz", hash = "sha256:55ca7c70a75689be937aa27f8ff4b018f06ff4838fc73045560bf0f5a1291060"}, ] [package.dependencies] @@ -2831,4 +3007,4 @@ test = ["pytest", "pytest-cov"] [metadata] lock-version = "2.1" python-versions = ">=3.13,!=3.14.1" -content-hash = "b89a42dd269e68aaf5515aaa786491a9ed3b3ff2e6742b6c3bb29ec68047412d" +content-hash = "4bf10225df8f9ad839ed957b95fd30f9c17b439bc078ef7fa402287870f8bbae" diff --git a/pyproject.toml b/pyproject.toml index 6db81aed..8758feb7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "gardenlinux" -version = "0.10.19" +version = "1.0.0" description = "Contains tools to work with the features directory of gardenlinux, for example deducting dependencies from feature sets or validating cnames" authors = ["Garden Linux Maintainers "] license = "Apache-2.0" @@ -10,47 +10,44 @@ packages = [{ include = "gardenlinux", from = "src" }] [tool.poetry.dependencies] python = ">=3.13,!=3.14.1" apt-repo = "^0.5" -boto3 = "^1.43.10" -click = "^8.4.0" +boto3 = "^1.43.108" cryptography = "^49.0.0" jsonschema = "^4.26.0" -networkx = "^3.6" -oras = "^0.2.38" -podman = "^5.6.0" -pygit2 = "^1.19.1" -pygments = "^2.19.2" -PyGithub = "^2.8.1" -PyYAML = "^6.0.2" -semver = "^3.0.4" +networkx = "^3.7" +oras = "^0.2.43" +podman = "^5.8.0" +pygit2 = "^1.20.1" +pygments = "^2.21.0" +PyGithub = "^2.10.0" +PyYAML = "^6.0.3" +semver = "^3.1.0" [tool.poetry.group.dev.dependencies] bandit = "^1.9.4" isort = "^8.0.1" moto = "^5.2.1" -pre-commit = "^4.6.0" +pre-commit = "^4.6.2" python-dotenv = "^1.2.2" -pytest = "^9.0.3" +pytest = "^9.1.1" pytest-cov = "^7.1.0" requests-mock = "^1.12.1" mypy = "2.1.0" -types-click = "^7.1.8" types-pyyaml = "^6.0.12.20260518" types-requests = "^2.33.0.20260518" boto3-stubs = { extras = ["s3"], version = "^1.42.41" } [tool.poetry.group.docs.dependencies] -sphinx-rtd-theme = "^3.0.2" -sphinx-click = "^6.2.0" +sphinx-rtd-theme = "^3.1.0" sphinxcontrib-autoprogram = "^0.1.8" -sphinx-markdown-builder = "^0.6.10" +sphinx-markdown-builder = "^0.6.11" [tool.poetry.scripts] -gl-cname = "gardenlinux.features.cname_main:main" gl-feature-fs-diff = "gardenlinux.features.reproducibility.__main__:main" gl-features-parse = "gardenlinux.features.__main__:main" gl-flavors-parse = "gardenlinux.flavors.__main__:main" gl-gh-release = "gardenlinux.github.release.__main__:main" gl-oci = "gardenlinux.oci.__main__:main" +gl-metadata = "gardenlinux.features.metadata_main:main" gl-s3 = "gardenlinux.s3.__main__:main" [tool.pytest.ini_options] diff --git a/src/gardenlinux/constants.py b/src/gardenlinux/constants.py index 5c2fe8ed..d61101e6 100644 --- a/src/gardenlinux/constants.py +++ b/src/gardenlinux/constants.py @@ -4,9 +4,9 @@ ARCHS = ["amd64", "arm64"] # GardenLinux "bare" feature -BARE_FLAVOR_FEATURE_CONTENT = {"description": "Bare flavor", "type": "platform"} +BARE_CNAME_FEATURE_CONTENT = {"description": "Bare flavor", "type": "platform"} -BARE_FLAVOR_LIBC_FEATURE_CONTENT = { +BARE_CNAME_LIBC_FEATURE_CONTENT = { "description": "Bare libc feature", "type": "element", } @@ -147,6 +147,7 @@ GL_BUG_REPORT_URL = "https://github.com/gardenlinux/gardenlinux/issues" GL_COMMIT_SPECIAL_VALUES = ("local",) +GL_VERSION_SPECIAL_VALUES = ("today",) GL_CONTAINER_REGISTRY_BASE_URL = "ghcr.io/gardenlinux/gardenlinux" GL_DEB_REPO_BASE_URL = "https://packages.gardenlinux.io/gardenlinux" GL_DISTRIBUTION_NAME = "Garden Linux" diff --git a/src/gardenlinux/features/__init__.py b/src/gardenlinux/features/__init__.py index a6e7692e..ed61af2f 100644 --- a/src/gardenlinux/features/__init__.py +++ b/src/gardenlinux/features/__init__.py @@ -4,7 +4,10 @@ Features module """ -from .cname import CName +from .artifact_base_name import ArtifactBaseName +from .c_name import CName +from .flavor import Flavor from .parser import Parser +from .versioned_flavor import VersionedFlavor -__all__ = ["CName", "Parser"] +__all__ = ["ArtifactBaseName", "CName", "Flavor", "Parser", "VersionedFlavor"] diff --git a/src/gardenlinux/features/__main__.py b/src/gardenlinux/features/__main__.py index d0b7f8ad..7cd2501e 100644 --- a/src/gardenlinux/features/__main__.py +++ b/src/gardenlinux/features/__main__.py @@ -6,31 +6,32 @@ """ import argparse -import logging import os import re from os import path from typing import Any, Set -from .cname import CName +from .artifact_base_name import ArtifactBaseName from .parser import Parser _ARGS_TYPE_ALLOWED = [ + "arch", + "artifact-base-name", "cname", - "cname_base", - "container_name", - "container_tag", - "commit_id", + "commit-id", + "container-name", + "container-tag", + "elements", "features", - "platform", - "platforms", "flags", "flavor", - "elements", - "arch", - "version", - "version_and_commit_id", "graph", + "platform", + "platform-variant", + "platforms", + "version", + "version_and_commit-id", + "versioned-flavor", ] RE_CAMEL_CASE_SPLITTER = re.compile("([A-Z]+|[a-z0-9])([A-Z])(?!$)") @@ -50,20 +51,25 @@ def get_parser() -> argparse.ArgumentParser: parser = argparse.ArgumentParser( prog="gl-features-parse", - description="Parse and extract information from GardenLinux features.", + description="Parse and extract information from Garden Linux features.", ) parser.add_argument( "--arch", dest="arch", - help="Target architecture (e.g., amd64, arm64). Overrides architecture from cname.", + help="Target architecture (e.g., amd64, arm64). Overrides architecture from CName.", + ) + + parser.add_argument( + "--artifact-base-name", + dest="artifact_base_name", + help="Artifact base name to parse. Must be a valid Garden Linux Artifact Base Name.", ) parser.add_argument( "--cname", dest="cname", - required=True, - help="Canonical name (cname) to parse. Must be a valid GardenLinux canonical name.", + help="Canonical Name (CName) to parse.", ) parser.add_argument( @@ -79,21 +85,23 @@ def get_parser() -> argparse.ArgumentParser: ) parser.add_argument( - "--release-file", - dest="release_file", - help="Path to a release file containing cname metadata. Either --feature-dir or --release-file must be provided.", + "--flavor", + dest="flavor", + help="Garden Linux flavor name.", ) parser.add_argument( - "--default-arch", - dest="default_arch", - help="Default architecture to use if architecture cannot be determined from cname or other sources.", + "--ignore", + dest="ignore", + type=lambda arg: set([f for f in arg.split(",") if f]), + default=set(), + help="Comma-separated list of features to ignore when processing (e.g., 'feature1,feature2').", ) parser.add_argument( - "--default-version", - dest="default_version", - help="Default version to use if version cannot be determined from files or other sources.", + "--release-file", + dest="release_file", + help="Path to a release file containing features metadata. Either --feature-dir or --release-file must be provided.", ) parser.add_argument( @@ -103,11 +111,9 @@ def get_parser() -> argparse.ArgumentParser: ) parser.add_argument( - "--ignore", - dest="ignore", - type=lambda arg: set([f for f in arg.split(",") if f]), - default=set(), - help="Comma-separated list of features to ignore when processing (e.g., 'feature1,feature2').", + "--versioned-flavor", + dest="versioned_flavor", + help="Garden Linux versioned flavor name.", ) parser.add_argument( @@ -133,143 +139,78 @@ def main() -> None: parser = get_parser() args = parser.parse_args() - assert bool(args.feature_dir) or bool(args.release_file), ( - "Please provide either `--feature_dir` or `--release_file` argument" + assert args.feature_dir or args.release_file or os.environ.get("GL_ROOT_DIR"), ( + "Please provide either `--feature-dir` or `--release-file` argument" ) arch = args.arch commit_id_or_hash = args.commit - gardenlinux_root = path.dirname(args.feature_dir) + gardenlinux_root = os.environ.get("GL_ROOT_DIR", path.dirname(args.feature_dir)) version = args.version - if arch is None or arch == "": - arch = args.default_arch - - if gardenlinux_root == "": + if not gardenlinux_root: gardenlinux_root = "." - if version is None or version == "": - try: - version, commit_id_or_hash = get_version_and_commit_id_from_files( - gardenlinux_root - ) - except RuntimeError as exc: - logging.debug( - "Failed to parse version information for GL root '{0}': {1}".format( - gardenlinux_root, exc - ) - ) - - version = args.default_version + if not version or not commit_id_or_hash: + version, commit_id_or_hash = ( + ArtifactBaseName.get_version_and_commit_id_from_files(gardenlinux_root) + ) - cname = CName(args.cname, arch=arch, commit_hash=commit_id_or_hash, version=version) + abn_object = ArtifactBaseName.new_instance( + args.artifact_base_name, + cname=args.cname, + flavor=args.flavor, + versioned_flavor=args.versioned_flavor, + arch=arch, + version=version, + commit_id_or_hash=commit_id_or_hash, + ) if args.release_file is not None: - cname.load_from_release_file(args.release_file) - - arch = cname.arch - flavor = cname.flavor - commit_id_or_hash = cname.commit_id - version = cname.version - - if (arch is None or arch == "") and ( - args.type in ("cname", "container_name", "arch") - ): - raise RuntimeError( - "Architecture could not be determined and no default architecture set" - ) + abn_object.load_from_release_file(args.release_file) - if (commit_id_or_hash is None or commit_id_or_hash == "") and ( - args.type in ("container_tag", "commit_id", "version_and_commit_id") - ): - raise RuntimeError("Commit ID not specified") - - if (version is None or version == "") and ( - args.type - in ( - "container_tag", - "commit_id", - "version", - "version_and_commit_id", - ) - ): - raise RuntimeError("Version not specified and no default version set") + arch = abn_object.arch + cname = abn_object.cname + commit_id_or_hash = abn_object.commit_id + version = abn_object.version feature_dir_name = path.basename(args.feature_dir) if args.type == "arch": print(arch) elif args.type in ( - "cname_base", + "artifact-base-name", "cname", - "container_name", + "container-name", "elements", "features", "flags", "flavor", "graph", "platform", + "platform-variant", "platforms", + "versioned-flavor", ): if args.type == "graph" or len(args.ignore) > 0: features_parser = Parser(gardenlinux_root, feature_dir_name) print_output_from_features_parser( - args.type, cname, features_parser, flavor, args.ignore + args.type, abn_object, features_parser, cname, args.ignore ) else: - print_output_from_cname(args.type, cname) - elif args.type == "commit_id": - print(commit_id_or_hash[:8]) # type: ignore[index] - elif args.type == "container_tag": - print(re.sub("\\W+", "-", f"{version}-{commit_id_or_hash[:8]}")) # type: ignore[index] + print_output_from_abn_object(args.type, abn_object) + elif args.type == "commit-id": + print(commit_id_or_hash[:8]) + elif args.type == "container-tag": + print(re.sub("\\W+", "-", f"{version}-{commit_id_or_hash[:8]}")) elif args.type == "version": print(version) - elif args.type == "version_and_commit_id": - print(f"{version}-{commit_id_or_hash[:8]}") # type: ignore[index] - - -def get_version_and_commit_id_from_files(gardenlinux_root: str) -> tuple[str, str]: - """ - Returns the version and commit ID based on files in the GardenLinux root directory. - - :param gardenlinux_root: GardenLinux root directory - - :return: (tuple) Version and commit ID if readable - :since: 0.7.0 - """ - - commit_hash = None - version = None - - if os.access(path.join(gardenlinux_root, "COMMIT"), os.R_OK): - with open(path.join(gardenlinux_root, "COMMIT"), "r") as fp: - commit_hash = fp.read().strip()[:8] - - if os.access(path.join(gardenlinux_root, "VERSION"), os.R_OK): - with open(path.join(gardenlinux_root, "VERSION"), "r") as fp: - version = fp.read().strip() - - if commit_hash is None or version is None: - raise RuntimeError("Failed to read version or commit ID from files") - - return (version, commit_hash) + elif args.type == "version_and_commit-id": + print(f"{version}-{commit_id_or_hash[:8]}") -def get_minimal_feature_set(graph: Any) -> Set[str]: - """ - Returns the minimal set of features described by the given graph. - - :param graph: networkx.Digraph - - :return: (set) Minimal set of features - :since: 0.7.0 - """ - - return set([node for (node, degree) in graph.in_degree() if degree == 0]) - - -def graph_as_mermaid_markup(flavor: str | None, graph: Any) -> str: +def graph_as_mermaid_markup(cname: str | None, graph: Any) -> str: """ Generates a mermaid.js representation of the graph. This is helpful to identify dependencies between features. @@ -277,17 +218,17 @@ def graph_as_mermaid_markup(flavor: str | None, graph: Any) -> str: Syntax docs: https://mermaid.js.org/syntax/flowchart.html?id=flowcharts-basic-syntax - :param flavor: Flavor name - :param graph: networkx.Digraph + :param cname: Garden Linux canonical name + :param graph: networkx.Digraph :return: (str) mermaid.js representation :since: 0.7.0 """ - if flavor is None: - raise RuntimeError("Error while generating graph: Flavor is None!") + if cname is None: + raise RuntimeError("Error while generating graph: CName is None!") - markup = f"---\ntitle: Dependency Graph for Feature {flavor}\n---\ngraph TD;\n" + markup = f"---\ntitle: Dependency Graph for Feature {cname}\n---\ngraph TD;\n" for u, v in graph.edges: markup += f" {u}-->{v};\n" @@ -297,9 +238,9 @@ def graph_as_mermaid_markup(flavor: str | None, graph: Any) -> str: def print_output_from_features_parser( output_type: str, - cname_instance: CName, + abn_object: ArtifactBaseName, parser: Parser, - flavor: str, + cname: str, ignores_list: Set[str], ) -> None: """ @@ -307,7 +248,7 @@ def print_output_from_features_parser( :param output_type: Output type :param parser: Features parser - :param flavor: Flavor + :param cname: Garden Linux canonical name :param ignores_list: Features to ignore :since: 1.0.0 @@ -316,54 +257,61 @@ def print_output_from_features_parser( def additional_filter_func(node: str) -> bool: return node not in ignores_list - if output_type == "features": - print( - parser.filter_as_string( - flavor, additional_filter_func=additional_filter_func + match output_type: + case "features": + print( + parser.filter_as_string( + cname, additional_filter_func=additional_filter_func + ) + ) + case "platform" | "platforms" | "elements" | "flags": + features_by_type = parser.filter_as_dict( + cname, additional_filter_func=additional_filter_func ) - ) - elif output_type in ("platform", "platforms", "elements", "flags"): - features_by_type = parser.filter_as_dict( - flavor, additional_filter_func=additional_filter_func - ) - - if output_type == "platform": - print(features_by_type["platform"][0]) - if output_type == "platforms": - print(",".join(features_by_type["platform"])) - elif output_type == "elements": - print(",".join(features_by_type["element"])) - elif output_type == "flags": - print(",".join(features_by_type["flag"])) - else: - graph = parser.filter(flavor, additional_filter_func=additional_filter_func) - - sorted_features = Parser.sort_graph_nodes(graph) - minimal_feature_set = get_minimal_feature_set(graph) - - sorted_minimal_features = Parser.subset(minimal_feature_set, sorted_features) - - cname_base = Parser.get_flavor_from_feature_set(sorted_minimal_features) - - if output_type == "cname_base": - print(cname_base) - elif output_type == "cname": - cname = flavor - - if cname_instance.arch is not None: - cname += f"-{cname_instance.arch}" - - if cname_instance.version_and_commit_id is not None: - cname += f"-{cname_instance.version_and_commit_id}" - - print(cname) - elif output_type == "container_name": - print(RE_CAMEL_CASE_SPLITTER.sub("\\1_\\2", cname_base).lower()) - elif output_type == "graph": - print(graph_as_mermaid_markup(flavor, graph)) + match output_type: + case "elements": + print(",".join(features_by_type["element"])) + case "flags": + print(",".join(features_by_type["flag"])) + case "platform": + print(features_by_type["platform"][0]) + case "platforms": + print(",".join(features_by_type["platform"])) + case "platform-variant": + print(abn_object.platform_variant) + case _: + graph = parser.filter(cname, additional_filter_func=additional_filter_func) + + sorted_features = Parser.sort_graph_nodes(graph) + minimal_feature_set = Parser.get_minimal_feature_set(graph) + + sorted_minimal_features = Parser.subset( + minimal_feature_set, sorted_features + ) -def print_output_from_cname(output_type: str, cname_instance: CName) -> None: + cname = Parser.get_cname_from_feature_set(sorted_minimal_features) + + match output_type: + case "artifact-base-name": + print( + f"{cname}-{abn_object.arch}-{abn_object.version_and_commit_id}" + ) + case "cname": + print(cname) + case "container-name": + print(RE_CAMEL_CASE_SPLITTER.sub("\\1_\\2", cname).lower()) + case "flavor": + print(f"{cname}-{abn_object.arch}") + case "graph": + print(graph_as_mermaid_markup(cname, graph)) + case "versioned-flavor": + print(f"{cname}-{abn_object.arch}-{abn_object.version}") + + +def print_output_from_abn_object( + output_type: str, abn_object: ArtifactBaseName +) -> None: """ Prints output to stdout based on the given CName instance. @@ -373,33 +321,35 @@ def print_output_from_cname(output_type: str, cname_instance: CName) -> None: :since: 1.0.0 """ - if output_type in ("cname_base", "cname", "flavor"): - sorted_features = Parser.get_flavor_as_feature_set(cname_instance.flavor) - flavor = Parser.get_flavor_from_feature_set(sorted_features) - - if output_type in ("cname_base", "flavor"): - print(flavor) - else: - if cname_instance.version_and_commit_id is None: - raise RuntimeError( - "Version and commit ID can't be provided without appropriate input." - ) - - print( - f"{flavor}-{cname_instance.arch}-{cname_instance.version_and_commit_id}" - ) - elif output_type == "container_name": - print(RE_CAMEL_CASE_SPLITTER.sub("\\1-\\2", cname_instance.flavor).lower()) - elif output_type == "platform": - print(cname_instance.platform) - elif output_type == "platforms": - print(cname_instance.feature_set_platform) - elif output_type == "elements": - print(cname_instance.feature_set_element) - elif output_type == "features": - print(cname_instance.feature_set) - elif output_type == "flags": - print(cname_instance.feature_set_flag) + match output_type: + case "artifact-base-name" | "cname" | "flavor" | "versioned-flavor": + cname = abn_object.cname + + match output_type: + case "artifact-base-name": + print( + f"{cname}-{abn_object.arch}-{abn_object.version_and_commit_id}" + ) + case "cname": + print(cname) + case "flavor": + print(f"{cname}-{abn_object.arch}") + case "versioned-flavor": + print(f"{cname}-{abn_object.arch}-{abn_object.version}") + case "container-name": + print(RE_CAMEL_CASE_SPLITTER.sub("\\1-\\2", abn_object.cname).lower()) + case "elements": + print(abn_object.feature_set_element) + case "features": + print(abn_object.feature_set) + case "flags": + print(abn_object.feature_set_flag) + case "platform": + print(abn_object.platform) + case "platform-variant": + print(abn_object.platform_variant) + case "platforms": + print(abn_object.feature_set_platform) if __name__ == "__main__": diff --git a/src/gardenlinux/features/artifact_base_name.py b/src/gardenlinux/features/artifact_base_name.py new file mode 100644 index 00000000..e4112471 --- /dev/null +++ b/src/gardenlinux/features/artifact_base_name.py @@ -0,0 +1,442 @@ +# -*- coding: utf-8 -*- + +""" +Artifact base name (ABN) +""" + +import os +import re +from configparser import UNNAMED_SECTION, ConfigParser +from os import PathLike +from pathlib import Path +from typing import Optional, Self + +from ..constants import ( + GL_BUG_REPORT_URL, + GL_COMMIT_SPECIAL_VALUES, + GL_DISTRIBUTION_NAME, + GL_HOME_URL, + GL_RELEASE_ID, + GL_SUPPORT_URL, + GL_VERSION_SPECIAL_VALUES, +) +from .versioned_flavor import VersionedFlavor + + +class ArtifactBaseName(VersionedFlavor): + """ + Class to represent an artifact base name (ABN). It can be parsed from any + file type. + + :author: Garden Linux Maintainers + :copyright: Copyright 2026 SAP SE + :package: gardenlinux + :subpackage: features + :since: 1.0.0 + :license: https://www.apache.org/licenses/LICENSE-2.0 + Apache License, Version 2.0 + """ + + def __init__( + self, + artifact: str, + ): + """ + Constructor __init__(ArtifactBaseName) + + :param artifact: Artifact name + + :since: 1.0.0 + """ + + re_object = re.compile( + "([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)-([a-z0-9]+)-([a-z0-9.]+)-([a-z0-9]+)(\\.|$)" + ) + + re_match = re_object.match(artifact) + + if not re_match: + raise ValueError(f"Not a valid Garden Linux artifact: {artifact}") + + commit_id_or_hash = re_match[5] + + self._commit_id = commit_id_or_hash[:8] + self._commit_hash = None + + if ( + len(commit_id_or_hash) == 40 + or commit_id_or_hash in GL_COMMIT_SPECIAL_VALUES + ): # sha1 hex + self._commit_hash = commit_id_or_hash + + VersionedFlavor.__init__(self, re_match[1], re_match[3], re_match[4]) + + @property + def commit_hash(self) -> Optional[str]: + """ + Returns the commit hash if part of the ABN parsed. + + :return: (str) Commit hash + :since: 1.0.0 + """ + + return self._commit_hash + + @commit_hash.setter + def commit_hash(self, commit_hash: str) -> None: + """ + Sets the commit hash + + :param commit_hash: Commit hash + + :since: 1.0.0 + """ + + if self._commit_id is not None and not commit_hash.startswith(self._commit_id): + raise RuntimeError("Commit hash given differs from commit ID already set") + + self._commit_id = commit_hash[:8] + self._commit_hash = commit_hash + + @property + def commit_id(self) -> str: + """ + Returns the commit ID if part of the ABN parsed. + + :return: (str) Commit ID + :since: 1.0.0 + """ + + return self._commit_id + + @property + def release_metadata_string(self) -> str: + """ + Returns the release metadata describing the given ABN instance. + + :return: (str) Release metadata + :since: 1.0.0 + """ + + commit_hash = self.commit_hash + commit_id = self.commit_id + platform_variant = self.platform_variant + version = self.version + + if commit_hash is None: + commit_hash = commit_id + + if platform_variant is None: + platform_variant = "" + + if version is None: + pretty_name = f"{GL_DISTRIBUTION_NAME} unsupported version" + version = "" + else: + pretty_name = f"{GL_DISTRIBUTION_NAME} {version}" + + metadata = f""" +ID={GL_RELEASE_ID} +ID_LIKE=debian +NAME="{GL_DISTRIBUTION_NAME}" +PRETTY_NAME="{pretty_name}" +IMAGE_VERSION={version} +VARIANT_ID="{self.flavor}" +HOME_URL="{GL_HOME_URL}" +SUPPORT_URL="{GL_SUPPORT_URL}" +BUG_REPORT_URL="{GL_BUG_REPORT_URL}" +GARDENLINUX_CNAME="{self.cname}" +GARDENLINUX_FEATURES="{self.feature_set}" +GARDENLINUX_FEATURES_PLATFORMS="{self.feature_set_platform}" +GARDENLINUX_FEATURES_ELEMENTS="{self.feature_set_element}" +GARDENLINUX_FEATURES_FLAGS="{self.feature_set_flag}" +GARDENLINUX_PLATFORM="{self.platform}" +GARDENLINUX_PLATFORM_VARIANT="{platform_variant}" +GARDENLINUX_VERSION="{version}" +GARDENLINUX_COMMIT_ID="{commit_id}" +GARDENLINUX_COMMIT_ID_LONG="{commit_hash}" + """.strip() + + return metadata + + @property + def version_and_commit_id(self) -> str: + """ + Returns the version and commit ID of the ABN parsed. + + :return: (str) Version and commit ID + :since: 1.0.0 + """ + + return f"{self.version}-{self.commit_id}" + + def __str__(self) -> str: + """ + Returns the Garden Linux artifact base name. + + :return: (str) Returns the ABN + :since: 1.0.0 + """ + + versioned_flavor = VersionedFlavor.__str__(self) + versioned_flavor += f"-{self.commit_id}" + + return versioned_flavor + + def _copy_from_instance(self, artifact_base_name: Self) -> None: + """ + Copies values from a given ABN instance. + + :param artifact_base_name: ABN instance + + :since: 1.0.0 + """ + + VersionedFlavor._copy_from_instance(self, artifact_base_name) + + self._commit_hash = artifact_base_name.commit_hash + self._commit_id = artifact_base_name.commit_id + + def load_from_release_file(self, release_file: PathLike[str] | str) -> None: + """ + Loads and parses a release metadata file. + + :param release_file: Release metadata file + + :since: 1.0.0 + """ + + artifact_base_name = self.__class__.new_from_release_file(release_file) + + if ( + artifact_base_name.flavor != self.flavor + or ( + self._commit_id is not None + and self._commit_id != artifact_base_name.commit_id + ) + or ( + self._version is not None + and self._version != artifact_base_name.version + ) + or ( + not self._flag_frankenstein + and artifact_base_name.platform + not in artifact_base_name.feature_set_platform + ) + ): + raise RuntimeError( + f"Release metadata file given is invalid: {release_file} failed consistency check - {self} != {artifact_base_name}" + ) + + self._copy_from_instance(artifact_base_name) + + def save_to_release_file( + self, release_file: PathLike[str] | str, overwrite: Optional[bool] = False + ) -> None: + """ + Saves the release metadata file. + + :param release_file: Release metadata file + + :since: 1.0.0 + """ + + if not isinstance(release_file, PathLike): + release_file = Path(release_file) + + if not overwrite and release_file.exists(): # type: ignore[attr-defined] + raise RuntimeError( + f"Refused to overwrite existing release metadata file: {release_file}" + ) + + with release_file.open("w") as fp: # type: ignore[attr-defined] + fp.write(self.release_metadata_string) + + @staticmethod + def new_from_release_file(release_file: PathLike[str] | str) -> "ArtifactBaseName": + """ + Loads and parses a release metadata file to return a new ABN instance. + + :param release_file: Release metadata file + + :return: (object) ABN instance + :since: 1.0.0 + """ + + if not isinstance(release_file, PathLike): + release_file = Path(release_file) + + if not release_file.exists(): # type: ignore[attr-defined] + raise RuntimeError( + f"Release metadata file given is invalid: {release_file}" + ) + + release_config = ConfigParser(allow_unnamed_section=True) + release_config.read(release_file) + + for release_field in ( + "VARIANT_ID", + "GARDENLINUX_COMMIT_ID_LONG", + "GARDENLINUX_FEATURES", + "GARDENLINUX_PLATFORM", + "GARDENLINUX_VERSION", + ): + if not release_config.has_option(UNNAMED_SECTION, release_field): + raise RuntimeError( + f"Release metadata file given is invalid: {release_file} misses {release_field}" + ) + + artifact_base_name = release_config.get(UNNAMED_SECTION, "VARIANT_ID").strip( + "\"'" + ) + + artifact_base_name += "-" + release_config.get( + UNNAMED_SECTION, "GARDENLINUX_VERSION" + ).strip("\"'") + + artifact_base_name += "-" + release_config.get( + UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG" + ).strip("\"'") + + abn_object = ArtifactBaseName(artifact_base_name) + + abn_object._feature_set_cached = release_config.get( + UNNAMED_SECTION, "GARDENLINUX_FEATURES" + ).strip("\"'") + + if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_ELEMENTS"): + abn_object._feature_elements_cached = ( + release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_ELEMENTS") + .strip("\"'") + .split(",") + ) + + if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS"): + abn_object._feature_flags_cached = ( + release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS") + .strip("\"'") + .split(",") + ) + + if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS"): + abn_object._feature_platforms_cached = ( + release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS") + .strip("\"'") + .split(",") + ) + + abn_object._platform_cached = release_config.get( + UNNAMED_SECTION, "GARDENLINUX_PLATFORM" + ).strip("\"'") + + if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT"): + abn_object._platform_variant_cached = release_config.get( + UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT" + ).strip("\"'") + + return abn_object + + @staticmethod + def get_version_and_commit_id_from_files( + gardenlinux_root: Path | str, + ) -> tuple[Optional[str], Optional[str]]: + """ + Returns the version and commit ID based on files in the GardenLinux root directory. + + :param gardenlinux_root: GardenLinux root directory + + :return: (tuple) Version and commit ID if readable; None for both values otherwise + :since: 1.0.0 + """ + + if not isinstance(gardenlinux_root, PathLike): + gardenlinux_root = Path(gardenlinux_root) + + commit_hash = None + version = None + + if os.access(gardenlinux_root.joinpath("COMMIT"), os.R_OK): + with gardenlinux_root.joinpath("COMMIT").open("r") as fp: + commit_hash = fp.read().strip()[:8] + + if os.access(gardenlinux_root.joinpath("VERSION"), os.R_OK): + with gardenlinux_root.joinpath("VERSION").open("r") as fp: + version = fp.read().strip() + + if commit_hash is None or version is None: + return (None, None) + + return (version, commit_hash) + + @staticmethod + def new_instance( + artifact_base_name: Optional[str] = None, + versioned_flavor: Optional[str] = None, + flavor: Optional[str] = None, + cname: Optional[str] = None, + arch: Optional[str] = None, + version: Optional[str] = None, + commit_id_or_hash: Optional[str] = None, + ) -> "ArtifactBaseName": + """ + Returns a new ABN instance based on various input data available. + + :param artifact_base_name: Artifact base name + :param versioned_flavor: Garden Linux versioned flavor + :param flavor: Garden Linux flavor + :param cname: Garden Linux Ccanonical Name + :param arch: Artifact architecture + :param version: Artifact version + :param commit_id_or_hash: Artifact commit ID or hash + + :return: (object) ABN instance + :since: 1.0.0 + """ + + if not artifact_base_name: + if versioned_flavor: + if not commit_id_or_hash: + raise ValueError("Argument missing: commit_id_or_hash") + + artifact_base_name = versioned_flavor + f"-{commit_id_or_hash}" + elif flavor: + if not version: + raise ValueError("Argument missing: version") + if not commit_id_or_hash: + raise ValueError("Argument missing: commit_id_or_hash") + + artifact_base_name = flavor + f"-{version}-{commit_id_or_hash}" + elif cname: + if not arch: + raise ValueError("Argument missing: arch") + if not version: + raise ValueError("Argument missing: version") + if not commit_id_or_hash: + raise ValueError("Argument missing: commit_id_or_hash") + + artifact_base_name = cname + f"-{arch}-{version}-{commit_id_or_hash}" + else: + raise ValueError( + "Argument missing: At least one of artifact_base_name, cname, flavor or versioned_flavor" + ) + + abn_object = ArtifactBaseName(artifact_base_name) + + if cname and abn_object.cname != cname: + raise RuntimeError("CName does not match the given argument") + if arch and abn_object.arch != arch: + raise RuntimeError("Architecture does not match the given argument") + if ( + version + and version not in GL_VERSION_SPECIAL_VALUES + and abn_object.version != version + ): + raise RuntimeError("Version does not match the given argument") + + if commit_id_or_hash: + if abn_object.commit_hash and abn_object.commit_hash != commit_id_or_hash: + raise RuntimeError("Commit hash does not match the given argument") + elif abn_object.commit_id != commit_id_or_hash: + raise RuntimeError("Commit ID does not match the given argument") + + return abn_object diff --git a/src/gardenlinux/features/c_name.py b/src/gardenlinux/features/c_name.py new file mode 100644 index 00000000..cdb6a2fa --- /dev/null +++ b/src/gardenlinux/features/c_name.py @@ -0,0 +1,235 @@ +# -*- coding: utf-8 -*- + +""" +Garden Linux Canonical Name (CName) +""" + +from os import environ +from typing import Any, Dict, List, Optional, Self + +from ..constants import GL_PLATFORM_FRANKENSTEIN +from .parser import Parser + + +class CName(object): + """ + Class to represent a Garden Linux Canonical Name (CName). + + :author: Garden Linux Maintainers + :copyright: Copyright 2024 SAP SE + :package: gardenlinux + :subpackage: features + :since: 1.0.0 + :license: https://www.apache.org/licenses/LICENSE-2.0 + Apache License, Version 2.0 + """ + + def __init__( + self, + cname: str, + ): + """ + Constructor __init__(CName) + + :param cname: CName to represent + + :since: 1.0.0 + """ + + self._cname = cname + self._feature_elements_cached: Optional[List[str]] = None + self._feature_flags_cached: Optional[List[str]] = None + self._feature_platforms_cached: Optional[List[str]] = None + self._feature_set_cached: Optional[str] = None + self._features_cached: Optional[Dict[str, Any]] = None + self._platform_cached: Optional[str] = None + self._platform_variant_cached: Optional[str] = None + + self._flag_frankenstein = bool(environ.get("GL_ALLOW_FRANKENSTEIN", False)) + + self._flag_multiple_platforms = bool( + environ.get("GL_ALLOW_MULTIPLE_PLATFORMS", False) + ) + + if self._flag_frankenstein: + self._flag_multiple_platforms = True + + @property + def cname(self) -> str: + """ + Returns the CName parsed. + + :return: (str) CName + :since: 0.7.0 + """ + + return self._cname + + @property + def features(self) -> Dict[str, Any]: + """ + Returns the features for the CName parsed. + + :return: (dict) Features of the CName + :since: 0.10.14 + """ + + if self._features_cached is None: + self._features_cached = Parser().filter_as_dict(self.cname) + + return self._features_cached + + @property + def feature_set(self) -> str: + """ + Returns the feature set for the CName parsed. + + :return: (str) Feature set of the CName + :since: 0.7.0 + """ + + if self._feature_set_cached is not None: + return self._feature_set_cached + + return Parser().filter_as_string(self.cname) + + @property + def feature_set_element(self) -> str: + """ + Returns the feature set of type "element" for the CName parsed. + + :return: (str) Feature set elements + :since: 1.0.0 + """ + + if self._feature_elements_cached is not None: + return ",".join(self._feature_elements_cached) + + return ",".join(self.features["element"]) + + @property + def feature_set_flag(self) -> str: + """ + Returns the feature set of type "flag" for the CName parsed. + + :return: (str) Feature set flags + :since: 1.0.0 + """ + + if self._feature_flags_cached is not None: + return ",".join(self._feature_flags_cached) + + return ",".join(self.features["flag"]) + + @property + def feature_set_platform(self) -> str: + """ + Returns the feature set of type "platform" for the CName parsed. + + :return: (str) Feature set platform + :since: 1.0.0 + """ + + if self._feature_platforms_cached is None: + platforms = self.features["platform"] + else: + platforms = self._feature_platforms_cached + + if self._flag_multiple_platforms: + return ",".join(platforms) + + assert len(platforms) < 2, "Only one platform is supported" + return platforms[0] # type: ignore[no-any-return] + + @property + def feature_set_list(self) -> List[str]: + """ + Returns the feature set for the CName parsed. + + :return: (list) Feature set list of the CName + :since: 0.10.12 + """ + + if self._feature_set_cached is not None: + return self._feature_set_cached.split(",") + + return Parser().filter_as_list(self.cname) + + @property + def platform(self) -> str: + """ + Returns the platform for the CName parsed. + + :return: (str) Platform + :since: 0.7.0 + """ + + if self._platform_cached is not None: + platforms = [self._platform_cached] + elif self._feature_platforms_cached is not None: + platforms = self._feature_platforms_cached + else: + platforms = self.features["platform"] + + if self._flag_frankenstein and len(platforms) > 1: + return GL_PLATFORM_FRANKENSTEIN + + if not self._flag_multiple_platforms: + assert len(platforms) < 2 + "Only one platform is supported" + + return platforms[0] + + @property + def platform_variant(self) -> Optional[str]: + """ + Returns the platform variant for the CName parsed. + + :return: (str) Platform variant + :since: 1.0.0 + """ + + if self._platform_variant_cached is not None: + return self._platform_variant_cached + + # @TODO: Platform variant is set by GardenLinux features to the release file. If not read or cached it is currently invisible for this library. + return None + + @platform_variant.setter + def platform_variant(self, variant: str) -> None: + """ + Sets the the platform variant + + :param variant: Platform variant + + :since: 1.0.0 + """ + + self._platform_variant_cached = variant + + def __str__(self) -> str: + """ + Returns the Garden Linux Canonical Name. + + :return: (str) Returns the Garden Linux Canonical Name + :since: 1.0.0 + """ + + return self.cname + + def _copy_from_instance(self, c_name: Self) -> None: + """ + Copies values from a given Garden Linux Canonical Name instance. + + :param cname_object: Garden Linux Canonical Name instance + + :since: 1.0.0 + """ + + self._cname = c_name.cname + self._feature_set_cached = c_name.feature_set + self._feature_elements_cached = c_name.feature_set_element.split(",") + self._feature_flags_cached = c_name.feature_set_flag.split(",") + self._feature_platforms_cached = c_name.feature_set_platform.split(",") + self._platform_cached = c_name.platform + self._platform_variant_cached = c_name.platform_variant diff --git a/src/gardenlinux/features/cname.py b/src/gardenlinux/features/cname.py deleted file mode 100644 index 98c9cc29..00000000 --- a/src/gardenlinux/features/cname.py +++ /dev/null @@ -1,613 +0,0 @@ -# -*- coding: utf-8 -*- - -""" -Canonical name (cname) -""" - -import re -from configparser import UNNAMED_SECTION, ConfigParser -from os import PathLike, environ -from pathlib import Path -from typing import Any, Dict, List, Optional, Self - -from ..constants import ( - ARCHS, - GL_BUG_REPORT_URL, - GL_DISTRIBUTION_NAME, - GL_HOME_URL, - GL_PLATFORM_FRANKENSTEIN, - GL_RELEASE_ID, - GL_SUPPORT_URL, -) -from .parser import Parser - - -class CName(object): - """ - Class to represent a canonical name (cname). - - :author: Garden Linux Maintainers - :copyright: Copyright 2024 SAP SE - :package: gardenlinux - :subpackage: features - :since: 0.7.0 - :license: https://www.apache.org/licenses/LICENSE-2.0 - Apache License, Version 2.0 - """ - - def __init__( - self, - cname: str, - arch: Optional[str] = None, - commit_hash: Optional[str] = None, - version: Optional[str] = None, - ): - """ - Constructor __init__(CName) - - :param cname: Canonical name to represent - :param arch: Architecture if not part of cname - :param commit_hash: Commit ID or hash if not part of cname - :param version: Version if not part of cname - - :since: 0.7.0 - """ - - self._arch = None - self._commit_hash = None - self._commit_id = None - self._feature_elements_cached: Optional[List[str]] = None - self._feature_flags_cached: Optional[List[str]] = None - self._feature_platforms_cached: Optional[List[str]] = None - self._feature_set_cached: Optional[str] = None - self._features_cached: Optional[Dict[str, Any]] = None - self._platform_cached: Optional[str] = None - self._platform_variant_cached: Optional[str] = None - self._flavor = "" - self._version = None - - self._flag_frankenstein = bool(environ.get("GL_ALLOW_FRANKENSTEIN", False)) - - self._flag_multiple_platforms = bool( - environ.get("GL_ALLOW_MULTIPLE_PLATFORMS", False) - ) - - if self._flag_frankenstein: - self._flag_multiple_platforms = True - - commit_id_or_hash = None - - if version is not None: - # Support version values formatted as - - if commit_hash is None: - re_match = re.match("([a-z0-9.]+)(-([a-z0-9]+))?$", version) - assert re_match, f"Not a valid version {version}" - - commit_id_or_hash = re_match[3] - version = re_match[1] - else: - commit_id_or_hash = commit_hash - - re_object = re.compile( - "([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)(-([a-z0-9]+)(-([a-z0-9.]+)-([a-z0-9]+))*)?$" - ) - - re_match = re_object.match(cname) - - # Workaround Garden Linux canonical names without mandatory final commit hash - if ( - not re_match - and commit_id_or_hash - and re.match( - "([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)(-([a-z0-9]+)(-([a-z0-9.]+))*)?$", - cname, - ) - ): - re_match = re_object.match(f"{cname}-{commit_id_or_hash}") - - assert re_match, f"Not a valid Garden Linux canonical name {cname}" - - if re_match.lastindex == 1: - self._flavor = re_match[1] - else: - if commit_id_or_hash is None: - commit_id_or_hash = re_match[7] - elif re_match.group(7) is not None: - assert commit_id_or_hash.startswith(re_match[7]), ( - f"Mismatch between Garden Linux canonical name '{cname}' and given commit ID '{commit_id_or_hash}' detected" - ) - - self._flavor = re_match[1] - self._version = re_match[6] - - if re_match[4] in ARCHS: - self._arch = re_match[4] - else: - self._flavor += re_match[3] - - if self._arch is None and arch is not None: - self._arch = arch - - if version is not None: - if self._version is None: - self._version = version - else: - assert version == self._version, ( - f"Mismatch between Garden Linux canonical name '{cname}' and given version '{version}' detected" - ) - - if commit_id_or_hash is not None: - self._commit_id = commit_id_or_hash[:8] - - if len(commit_id_or_hash) == 40 or commit_id_or_hash == "local": # sha1 hex - self._commit_hash = commit_id_or_hash - - @property - def arch(self) -> Optional[str]: - """ - Returns the architecture for the cname parsed. - - :return: (str) CName architecture - :since: 0.7.0 - """ - - return self._arch - - @property - def cname(self) -> str: - """ - Returns the cname parsed. - - :return: (str) CName - :since: 0.7.0 - """ - - cname = self._flavor - - if self._arch is not None: - cname += f"-{self._arch}" - - if self._commit_id is not None and self._version is not None: - cname += f"-{self.version_and_commit_id}" - - return cname - - @property - def commit_hash(self) -> Optional[str]: - """ - Returns the commit hash if part of the cname parsed. - - :return: (str) Commit hash - :since: 1.0.0 - """ - - return self._commit_hash - - @commit_hash.setter - def commit_hash(self, commit_hash: str) -> None: - """ - Sets the commit hash - - :param commit_hash: Commit hash - - :since: 1.0.0 - """ - - if self._commit_id is not None and not commit_hash.startswith(self._commit_id): - raise RuntimeError("Commit hash given differs from commit ID already set") - - self._commit_id = commit_hash[:8] - self._commit_hash = commit_hash - - @property - def commit_id(self) -> Optional[str]: - """ - Returns the commit ID if part of the cname parsed. - - :return: (str) Commit ID - :since: 0.7.0 - """ - - return self._commit_id - - @property - def flavor(self) -> str: - """ - Returns the flavor for the cname parsed. - - :return: (str) Flavor - :since: 0.7.0 - """ - - return self._flavor - - @property - def features(self) -> Dict[str, Any]: - """ - Returns the features for the cname parsed. - - :return: (dict) Features of the cname - :since: 0.10.14 - """ - - if self._features_cached is None: - self._features_cached = Parser().filter_as_dict(self.flavor) - - return self._features_cached - - @property - def feature_set(self) -> str: - """ - Returns the feature set for the cname parsed. - - :return: (str) Feature set of the cname - :since: 0.7.0 - """ - - if self._feature_set_cached is not None: - return self._feature_set_cached - - return Parser().filter_as_string(self.flavor) - - @property - def feature_set_element(self) -> str: - """ - Returns the feature set of type "element" for the cname parsed. - - :return: (str) Feature set elements - :since: 1.0.0 - """ - - if self._feature_elements_cached is not None: - return ",".join(self._feature_elements_cached) - - return ",".join(self.features["element"]) - - @property - def feature_set_flag(self) -> str: - """ - Returns the feature set of type "flag" for the cname parsed. - - :return: (str) Feature set flags - :since: 1.0.0 - """ - - if self._feature_flags_cached is not None: - return ",".join(self._feature_flags_cached) - - return ",".join(self.features["flag"]) - - @property - def feature_set_platform(self) -> str: - """ - Returns the feature set of type "platform" for the cname parsed. - - :return: (str) Feature set platform - :since: 1.0.0 - """ - - if self._feature_platforms_cached is None: - platforms = self.features["platform"] - else: - platforms = self._feature_platforms_cached - - if self._flag_multiple_platforms: - return ",".join(platforms) - - assert len(platforms) < 2 - "Only one platform is supported" - return platforms[0] # type: ignore[no-any-return] - - @property - def feature_set_list(self) -> List[str]: - """ - Returns the feature set for the cname parsed. - - :return: (list) Feature set list of the cname - :since: 0.10.12 - """ - - if self._feature_set_cached is not None: - return self._feature_set_cached.split(",") - - return Parser().filter_as_list(self.flavor) - - @property - def platform(self) -> str: - """ - Returns the platform for the cname parsed. - - :return: (str) Platform - :since: 0.7.0 - """ - - if self._platform_cached is not None: - platforms = [self._platform_cached] - elif self._feature_platforms_cached is not None: - platforms = self._feature_platforms_cached - else: - platforms = self.features["platform"] - - if self._flag_frankenstein and len(platforms) > 1: - return GL_PLATFORM_FRANKENSTEIN - - if not self._flag_multiple_platforms: - assert len(platforms) < 2 - "Only one platform is supported" - - return platforms[0] - - @property - def platform_variant(self) -> Optional[str]: - """ - Returns the platform variant for the cname parsed. - - :return: (str) Platform variant - :since: 1.0.0 - """ - - if self._platform_variant_cached is not None: - return self._platform_variant_cached - - # @TODO: Platform variant is set by GardenLinux features to the release file. If not read or cached it is currently invisible for this library. - return None - - @platform_variant.setter - def platform_variant(self, variant: str) -> None: - """ - Sets the the platform variant - - :param variant: Platform variant - - :since: 1.0.0 - """ - - self._platform_variant_cached = variant - - @property - def release_metadata_string(self) -> str: - """ - Returns the release metadata describing the given CName instance. - - :return: (str) Release metadata describing the given CName instance - :since: 1.0.0 - """ - - commit_hash = self.commit_hash - commit_id = self.commit_id - platform_variant = self.platform_variant - version = self.version - - if commit_id is None: - commit_id = "" - - if commit_hash is None: - commit_hash = commit_id - - if platform_variant is None: - platform_variant = "" - - if version is None: - pretty_name = f"{GL_DISTRIBUTION_NAME} unsupported version" - version = "" - else: - pretty_name = f"{GL_DISTRIBUTION_NAME} {version}" - - metadata = f""" -ID={GL_RELEASE_ID} -ID_LIKE=debian -NAME="{GL_DISTRIBUTION_NAME}" -PRETTY_NAME="{pretty_name}" -IMAGE_VERSION={version} -VARIANT_ID="{self.flavor}-{self.arch}" -HOME_URL="{GL_HOME_URL}" -SUPPORT_URL="{GL_SUPPORT_URL}" -BUG_REPORT_URL="{GL_BUG_REPORT_URL}" -GARDENLINUX_CNAME="{self.cname}" -GARDENLINUX_FEATURES="{self.feature_set}" -GARDENLINUX_FEATURES_PLATFORMS="{self.feature_set_platform}" -GARDENLINUX_FEATURES_ELEMENTS="{self.feature_set_element}" -GARDENLINUX_FEATURES_FLAGS="{self.feature_set_flag}" -GARDENLINUX_PLATFORM="{self.platform}" -GARDENLINUX_PLATFORM_VARIANT="{platform_variant}" -GARDENLINUX_VERSION="{version}" -GARDENLINUX_COMMIT_ID="{commit_id}" -GARDENLINUX_COMMIT_ID_LONG="{commit_hash}" - """.strip() - - return metadata - - @property - def version(self) -> Optional[str]: - """ - Returns the version if part of the cname parsed. - - :return: (str) Version - :since: 0.7.0 - """ - - return self._version - - @property - def version_and_commit_id(self) -> Optional[str]: - """ - Returns the version and commit ID if part of the cname parsed. - - :return: (str) Version and commit ID - :since: 0.7.0 - """ - - if self._version is None or self._commit_id is None: - return None - - return f"{self._version}-{self._commit_id}" - - @property - def version_epoch(self) -> Optional[int]: - """ - Returns the GardenLinux version epoch of the cname parsed. - - :return: (str) GardenLinux version epoch - :since: 1.0.0 - """ - - epoch = None - - if self._version is not None and "." in self._version: - epoch = int(self._version.split(".", 1)[0]) - - return epoch - - def _copy_from_cname_object(self, cname_object: Self) -> None: - """ - Copies values from a given Garden Linux canonical name instance. - - :param cname_object: Garden Linux canonical name instance - - :since: 1.0.0 - """ - - self._arch = cname_object.arch - self._commit_hash = cname_object.commit_hash - self._commit_id = cname_object.commit_id - self._feature_set_cached = cname_object.feature_set - self._feature_elements_cached = cname_object.feature_set_element.split(",") - self._feature_flags_cached = cname_object.feature_set_flag.split(",") - self._feature_platforms_cached = cname_object.feature_set_platform.split(",") - self._platform_cached = cname_object.platform - self._platform_variant_cached = cname_object.platform_variant - self._version = cname_object.version - - def load_from_release_file(self, release_file: PathLike[str] | str) -> None: - """ - Loads and parses a release metadata file. - - :param release_file: Release metadata file - - :since: 1.0.0 - """ - - cname_object = CName.new_from_release_file(release_file) - - if ( - cname_object.flavor != self.flavor - or ( - self._commit_id is not None - and self._commit_id != cname_object.commit_id - ) - or (self._version is not None and self._version != cname_object.version) - or ( - not self._flag_frankenstein - and cname_object.platform not in cname_object.feature_set_platform - ) - ): - raise RuntimeError( - f"Release metadata file given is invalid: {release_file} failed consistency check - {self.cname} != {cname_object.cname}" - ) - - self._copy_from_cname_object(cname_object) - - def save_to_release_file( - self, release_file: PathLike[str] | str, overwrite: Optional[bool] = False - ) -> None: - """ - Saves the release metadata file. - - :param release_file: Release metadata file - - :since: 1.0.0 - """ - - if not isinstance(release_file, PathLike): - release_file = Path(release_file) - - if not overwrite and release_file.exists(): # type: ignore[attr-defined] - raise RuntimeError( - f"Refused to overwrite existing release metadata file: {release_file}" - ) - - with release_file.open("w") as fp: # type: ignore[attr-defined] - fp.write(self.release_metadata_string) - - @staticmethod - def new_from_release_file(release_file: PathLike[str] | str) -> "CName": - """ - Loads and parses a release metadata file. - - :param release_file: Release metadata file - - :since: 0.10.10 - """ - - if not isinstance(release_file, PathLike): - release_file = Path(release_file) - - if not release_file.exists(): # type: ignore[attr-defined] - raise RuntimeError( - f"Release metadata file given is invalid: {release_file}" - ) - - release_config = ConfigParser(allow_unnamed_section=True) - release_config.read(release_file) - - for release_field in ( - "GARDENLINUX_CNAME", - "GARDENLINUX_COMMIT_ID_LONG", - "GARDENLINUX_FEATURES", - "GARDENLINUX_PLATFORM", - "GARDENLINUX_VERSION", - ): - if not release_config.has_option(UNNAMED_SECTION, release_field): - raise RuntimeError( - f"Release metadata file given is invalid: {release_file} misses {release_field}" - ) - - commit_hash = release_config.get( - UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG" - ).strip("\"'") - - version = release_config.get(UNNAMED_SECTION, "GARDENLINUX_VERSION").strip( - "\"'" - ) - - cname_object = CName( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME").strip("\"'"), - commit_hash=commit_hash, - version=version, - ) - - cname_object._feature_set_cached = release_config.get( - UNNAMED_SECTION, "GARDENLINUX_FEATURES" - ).strip("\"'") - - if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_ELEMENTS"): - cname_object._feature_elements_cached = ( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_ELEMENTS") - .strip("\"'") - .split(",") - ) - - if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS"): - cname_object._feature_flags_cached = ( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_FLAGS") - .strip("\"'") - .split(",") - ) - - if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS"): - cname_object._feature_platforms_cached = ( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_FEATURES_PLATFORMS") - .strip("\"'") - .split(",") - ) - - cname_object._platform_cached = release_config.get( - UNNAMED_SECTION, "GARDENLINUX_PLATFORM" - ).strip("\"'") - - if release_config.has_option(UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT"): - cname_object._platform_variant_cached = release_config.get( - UNNAMED_SECTION, "GARDENLINUX_PLATFORM_VARIANT" - ).strip("\"'") - - return cname_object diff --git a/src/gardenlinux/features/cname_main.py b/src/gardenlinux/features/cname_main.py deleted file mode 100644 index 5ce5998c..00000000 --- a/src/gardenlinux/features/cname_main.py +++ /dev/null @@ -1,131 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -""" -gl-cname main entrypoint -""" - -import argparse -import logging -import re -from os.path import basename, dirname - -from .__main__ import ( - get_minimal_feature_set, - get_version_and_commit_id_from_files, -) -from .cname import CName -from .parser import Parser - - -def get_parser() -> argparse.ArgumentParser: - """ - Get the argument parser for gl-cname. - Used for documentation generation. - - :return: ArgumentParser instance - :since: 1.0.0 - """ - - parser = argparse.ArgumentParser( - prog="gl-cname", - description="Generate a canonical name (cname) from feature sets.", - ) - - parser.add_argument( - "--arch", - dest="arch", - help="Target architecture (e.g., amd64, arm64). If not specified, will be determined from the cname or feature set.", - ) - - parser.add_argument( - "--commit", - dest="commit", - help="Git commit hash. If not specified, will be read from COMMIT file in the GardenLinux root directory.", - ) - - parser.add_argument( - "--feature-dir", - default="features", - help="Path to the features directory (default: 'features').", - ) - - parser.add_argument( - "--version", - dest="version", - help="Version string. If not specified, will be read from VERSION file in the GardenLinux root directory.", - ) - - parser.add_argument( - "cname", - help="Canonical name (cname) to process. Must be a valid GardenLinux canonical name format.", - ) - - return parser - - -def main() -> None: - """ - gl-cname main() - - :since: 0.7.0 - """ - - parser = get_parser() - args = parser.parse_args() - - re_match = re.match( - "([a-zA-Z0-9]+([\\_\\-][a-zA-Z0-9]+)*?)(-([a-z0-9]+)(-([a-z0-9.]+)-([a-z0-9]+))*)?$", - args.cname, - ) - - assert re_match, f"Not a valid Garden Linux canonical name {args.cname}" - - arch = args.arch - commit_id_or_hash = args.commit - gardenlinux_root = dirname(args.feature_dir) - version = args.version - - if gardenlinux_root == "": - gardenlinux_root = "." - - if not version: - try: - version, commit_id_or_hash = get_version_and_commit_id_from_files( - gardenlinux_root - ) - except RuntimeError as exc: - logging.warning( - "Failed to parse version information for GL root '{0}': {1}".format( - gardenlinux_root, exc - ) - ) - - cname = CName(args.cname, arch=arch, commit_hash=commit_id_or_hash, version=version) - - assert cname.arch, "Architecture could not be determined" - - feature_dir_name = basename(args.feature_dir) - - if gardenlinux_root == "": - gardenlinux_root = "." - - graph = Parser(gardenlinux_root, feature_dir_name).filter(cname.flavor) - - sorted_features = Parser.sort_graph_nodes(graph) - minimal_feature_set = get_minimal_feature_set(graph) - - sorted_minimal_features = Parser.subset(minimal_feature_set, sorted_features) - - generated_cname = Parser.get_flavor_from_feature_set(sorted_minimal_features) - - generated_cname += f"-{cname.arch}" - - if cname.version_and_commit_id is not None: - generated_cname += f"-{cname.version_and_commit_id}" - - print(generated_cname) - - -if __name__ == "__main__": - main() diff --git a/src/gardenlinux/features/flavor.py b/src/gardenlinux/features/flavor.py new file mode 100644 index 00000000..9c9f7ce7 --- /dev/null +++ b/src/gardenlinux/features/flavor.py @@ -0,0 +1,88 @@ +# -*- coding: utf-8 -*- + +""" +Garden Linux flavor +""" + +from typing import Self + +from .c_name import CName + + +class Flavor(CName): + """ + Class to represent a Garden Linux flavor. + + :author: Garden Linux Maintainers + :copyright: Copyright 2026 SAP SE + :package: gardenlinux + :subpackage: features + :since: 1.0.0 + :license: https://www.apache.org/licenses/LICENSE-2.0 + Apache License, Version 2.0 + """ + + def __init__( + self, + cname: str, + arch: str, + ): + """ + Constructor __init__(Flavor) + + :param cname: CName to represent + :param arch: Architecture if not part of cname + + :since: 1.0.0 + """ + + CName.__init__(self, cname) + self._arch = arch + + @property + def arch(self) -> str: + """ + Returns the architecture for the CName parsed. + + :return: (str) CName architecture + :since: 0.7.0 + """ + + return self._arch + + @property + def flavor(self) -> str: + """ + Returns the Garden Linux flavor parsed. + + :return: (str) Flavor + :since: 0.7.0 + """ + + flavor = CName.__str__(self) + flavor += f"-{self.arch}" + + return flavor + + def __str__(self) -> str: + """ + Returns the Garden Linux flavor. + + :return: (str) Flavor + :since: 1.0.0 + """ + + return self.flavor + + def _copy_from_instance(self, flavor: Self) -> None: + """ + Copies values from a given Garden Linux flavor instance. + + :param cname_object: Flavor instance + + :since: 1.0.0 + """ + + CName._copy_from_instance(self, flavor) + + self._arch = flavor.arch diff --git a/src/gardenlinux/features/metadata_main.py b/src/gardenlinux/features/metadata_main.py index 9bb2c1d7..99825b89 100644 --- a/src/gardenlinux/features/metadata_main.py +++ b/src/gardenlinux/features/metadata_main.py @@ -6,8 +6,9 @@ """ import argparse +from os import environ -from .cname import CName +from .artifact_base_name import ArtifactBaseName _ARGS_ACTION_ALLOWED = [ "output-release-metadata", @@ -15,21 +16,74 @@ ] -def main() -> None: +def get_parser() -> argparse.ArgumentParser: """ - gl-metadata main() + Get the argument parser for gl-metadata. + Used for documentation generation. - :since: 0.7.0 + :return: ArgumentParser instance + :since: 1.0.0 """ - parser = argparse.ArgumentParser() + parser = argparse.ArgumentParser( + prog="gl-metadata", + description="Handle GardenLinux metadata reading and writing.", + ) + + parser.add_argument( + "--arch", + dest="arch", + help="Target architecture (e.g., amd64, arm64). Overrides architecture from CName.", + ) + + parser.add_argument( + "--artifact-base-name", + dest="artifact_base_name", + help="Artifact base name to parse. Must be a valid Garden Linux Artifact Base Name.", + ) + + parser.add_argument( + "--cname", + dest="cname", + help="Canonical Name (CName) to parse.", + ) + + parser.add_argument( + "--commit", + dest="commit", + help="Git commit hash. If not specified, will be read from COMMIT file or release file.", + ) + + parser.add_argument( + "--flavor", + dest="flavor", + help="GardenLinux flavor name.", + ) + + parser.add_argument( + "--release-file", + dest="release_file", + help="Path to a release file containing features metadata.", + ) + + parser.add_argument( + "--overwrite-file", + type=bool, + dest="overwrite_file", + help="Accept overwriting existing files.", + ) - parser.add_argument("--arch", dest="arch") - parser.add_argument("--cname", required=True, dest="cname") - parser.add_argument("--commit-hash", dest="commit_hash") - parser.add_argument("--release-file", dest="release_file") - parser.add_argument("--overwrite-file", type=bool, dest="overwrite_file") - parser.add_argument("--version", dest="version") + parser.add_argument( + "--version", + dest="version", + help="Version string. If not specified, will be read from VERSION file or release file.", + ) + + parser.add_argument( + "--versioned-flavor", + dest="versioned_flavor", + help="GardenLinux versioned flavor name.", + ) parser.add_argument( "action", @@ -38,22 +92,48 @@ def main() -> None: default="output-release-metadata", ) + return parser + + +def main() -> None: + """ + gl-metadata main() + + :since: 0.7.0 + """ + + parser = get_parser() args = parser.parse_args() - cname = CName( - args.cname, arch=args.arch, commit_hash=args.commit_hash, version=args.version + commit_id_or_hash = args.commit + gardenlinux_root = environ.get("GL_ROOT_DIR") + version = args.version + + if not gardenlinux_root: + gardenlinux_root = "." + + if not version or not commit_id_or_hash: + version, commit_id_or_hash = ( + ArtifactBaseName.get_version_and_commit_id_from_files(gardenlinux_root) + ) + + abn_object = ArtifactBaseName.new_instance( + args.artifact_base_name, + cname=args.cname, + flavor=args.flavor, + versioned_flavor=args.versioned_flavor, + arch=args.arch, + version=args.version, + commit_id_or_hash=args.commit, ) - if args.commit_hash is not None: - cname.commit_hash = args.commit_hash - if args.action == "write": - cname.save_to_release_file(args.release_file, args.overwrite_file) + abn_object.save_to_release_file(args.release_file, args.overwrite_file) else: if args.release_file is not None: - cname.load_from_release_file(args.release_file) + abn_object.load_from_release_file(args.release_file) - print(cname.release_metadata_string) + print(abn_object.release_metadata_string) if __name__ == "__main__": diff --git a/src/gardenlinux/features/parser.py b/src/gardenlinux/features/parser.py index 497e66fb..a282bbea 100644 --- a/src/gardenlinux/features/parser.py +++ b/src/gardenlinux/features/parser.py @@ -14,7 +14,7 @@ import networkx import yaml -from ..constants import BARE_FLAVOR_FEATURE_CONTENT, BARE_FLAVOR_LIBC_FEATURE_CONTENT +from ..constants import BARE_CNAME_FEATURE_CONTENT, BARE_CNAME_LIBC_FEATURE_CONTENT from ..logger import LoggerSetup @@ -70,7 +70,9 @@ def __init__( self._logger = logger self._logger.debug( - "features.Parser initialized for directory: {0}".format(feature_base_dir) + "gardenlinux.features.Parser initialized for directory: {0}".format( + feature_base_dir + ) ) @property @@ -132,7 +134,7 @@ def filter( :since: 0.7.0 """ - feature_set = Parser.get_flavor_as_feature_set(cname) + feature_set = Parser.get_cname_as_feature_set(cname) return self.filter_based_on_feature_set( feature_set, ignore_excludes, additional_filter_func @@ -278,9 +280,9 @@ def filter_based_on_feature_set( # @TODO: Remove "special" handling once "bare" is a first-class citizen of the feature graph if "bare" in feature_set: if not self.graph.has_node("bare"): - self.graph.add_node("bare", content=BARE_FLAVOR_FEATURE_CONTENT) + self.graph.add_node("bare", content=BARE_CNAME_FEATURE_CONTENT) if not self.graph.has_node("libc"): - self.graph.add_node("libc", content=BARE_FLAVOR_LIBC_FEATURE_CONTENT) + self.graph.add_node("libc", content=BARE_CNAME_LIBC_FEATURE_CONTENT) for feature in feature_set: for node in networkx.descendants( @@ -363,22 +365,36 @@ def _read_feature_yaml(self, feature_yaml_file: str) -> Dict[str, Any]: return {"name": name, "content": content} @staticmethod - def get_flavor_from_feature_set(sorted_features: List[str]) -> str: + def get_cname_from_feature_set(feature_set_list: List[str]) -> str: """ Get the base cname for the feature set given. - :param sorted_features: Sorted feature set + :param feature_set_list: Feature set list - :return: (str) Base cname - :since: 0.7.0 + :return: (str) Garden Linux canonical name + :since: 1.0.0 """ + if not feature_set_list: + raise ValueError("At least one platform must be given as a feature") + + platform = feature_set_list.pop(0) + features = [] + flags = [] + + for feature in feature_set_list: + if feature[:1] == "_": + flags.append(feature) + else: + features.append(feature) + return reduce( - lambda a, b: a + ("-" if not b.startswith("_") else "") + b, sorted_features + lambda a, b: a + ("-" if not b.startswith("_") else "") + b, + [platform] + sorted(features) + sorted(flags), ) @staticmethod - def get_flavor_as_feature_set(cname: str) -> List[str]: + def get_cname_as_feature_set(cname: str) -> List[str]: """ Returns the features of a given canonical name. @@ -478,6 +494,19 @@ def _get_graph_node_type(node: str) -> str: return node.get("content", {}).get("type") # type: ignore[attr-defined, no-any-return] + @staticmethod + def get_minimal_feature_set(graph: networkx.Graph) -> Set[str]: + """ + Returns the minimal set of features described by the given graph. + + :param graph: networkx.Graph + + :return: (set) Minimal set of features + :since: 1.0.0 + """ + + return set([node for (node, degree) in graph.in_degree() if degree == 0]) + @staticmethod def set_default_gardenlinux_root_dir(root_dir: str) -> None: """ diff --git a/src/gardenlinux/features/reproducibility/diff_parser.py b/src/gardenlinux/features/reproducibility/diff_parser.py index 319622d0..924fb3b1 100644 --- a/src/gardenlinux/features/reproducibility/diff_parser.py +++ b/src/gardenlinux/features/reproducibility/diff_parser.py @@ -59,9 +59,9 @@ def __init__( self.all_flavors: set[str] = set() self.reproducible_flavors: set[str] = set() self.passed_by_whitelist: set[str] = set() - self.expected_falvors: set[str] = set() + self.expected_flavors: set[str] = set() self.missing_flavors: set[str] = set() - self.unexpected_falvors: set[str] = set() + self.unexpected_flavors: set[str] = set() def sort_features(self, graph: nx.DiGraph) -> list[str]: """ @@ -97,17 +97,17 @@ def parse( diff_dir = Path(self._gardenlinux_root).joinpath(diff_dir) - self.expected_falvors = { - f"{variant['flavor']}-{variant['arch']}" + self.expected_flavors = { + f"{variant['cname']}-{variant['arch']}" for variant in (flavors_matrix["include"] + bare_flavors_matrix["include"]) } - for flavor in os.listdir(diff_dir): - if flavor.endswith(self._SUFFIX): - with open(diff_dir.joinpath(flavor), "r") as f: + for artifact in os.listdir(diff_dir): + if artifact.endswith(self._SUFFIX): + with open(diff_dir.joinpath(artifact), "r") as f: content = f.read() - flavor = flavor.rstrip(self._SUFFIX) + flavor = artifact.rstrip(self._SUFFIX) self.all_flavors.add(flavor) if content == "": self.reproducible_flavors.add(flavor) @@ -117,8 +117,8 @@ def parse( else: non_reproducible_flavors[flavor] = content.split("\n")[:-1] - self.missing_flavors = self.expected_falvors - self.all_flavors - self.unexpected_falvors = self.all_flavors - self.expected_falvors + self.missing_flavors = self.expected_flavors - self.all_flavors + self.unexpected_flavors = self.all_flavors - self.expected_flavors # Map files to flavors affected_flavors: Dict[str, set[str]] = {} # {file: {flavors...}} diff --git a/src/gardenlinux/features/reproducibility/markdown_formatter.py b/src/gardenlinux/features/reproducibility/markdown_formatter.py index 86e9f546..a0040288 100644 --- a/src/gardenlinux/features/reproducibility/markdown_formatter.py +++ b/src/gardenlinux/features/reproducibility/markdown_formatter.py @@ -190,19 +190,19 @@ def _header( 100 * ( len(self._diff_parser.reproducible_flavors) - / len(self._diff_parser.expected_falvors) + / len(self._diff_parser.expected_flavors) ), 1, ) emoji = ( "✅" - if len(self._diff_parser.expected_falvors) + if len(self._diff_parser.expected_flavors) == len(self._diff_parser.reproducible_flavors) else ("⚠️" if successrate >= SUCCESS_TRESHOLD else "❌") ) - total_count = len(self._diff_parser.expected_falvors) + total_count = len(self._diff_parser.expected_flavors) problem_count = ( "" @@ -226,18 +226,18 @@ def _header( + "" ) - if len(self._diff_parser.unexpected_falvors) > 0: + if len(self._diff_parser.unexpected_flavors) > 0: # This should never happen, but print a warning if it somehow does explanation += ( "\n\n
⁉️ These flavors were not expected to appear in the results, please check for errors in the workflow\
"
-                + "
".join(sorted(self._diff_parser.unexpected_falvors)) + + "
".join(sorted(self._diff_parser.unexpected_flavors)) + "
" ) explanation += ( "" - if len(self._diff_parser.expected_falvors) + if len(self._diff_parser.expected_flavors) <= len(self._diff_parser.reproducible_flavors) else "\n\n*The mentioned features are included in every affected flavor and not included in every unaffected flavor.*" ) @@ -270,7 +270,7 @@ def _table( if len(self._diff_parser.missing_flavors) > 0: row = "|❌ Workflow run did not produce any results|" - row += f"**{round(100 * (len(self._diff_parser.missing_flavors) / len(self._diff_parser.expected_falvors)), 1)}%** affected
" + row += f"**{round(100 * (len(self._diff_parser.missing_flavors) / len(self._diff_parser.expected_flavors)), 1)}%** affected
" row += self._dropdown(self._diff_parser.missing_flavors) row += "|No analysis available|\n" rows += row @@ -285,7 +285,7 @@ def sorting_function(files: frozenset[str]) -> tuple[int, str]: row = "|" row += self._dropdown(files) row += "|" - row += f"**{round(100 * (len(flavors) / len(self._diff_parser.expected_falvors)), 1)}%** affected
" + row += f"**{round(100 * (len(flavors) / len(self._diff_parser.expected_flavors)), 1)}%** affected
" row += self._dropdown(flavors) row += "|" if len(tree) == 0: @@ -300,7 +300,7 @@ def sorting_function(files: frozenset[str]) -> tuple[int, str]: row = "|" row += "✅ No problems found" row += "|" - row += f"**{round(100 * (len(self._diff_parser.reproducible_flavors) / len(self._diff_parser.expected_falvors)), 1)}%**
" + row += f"**{round(100 * (len(self._diff_parser.reproducible_flavors) / len(self._diff_parser.expected_flavors)), 1)}%**
" row += self._dropdown(self._diff_parser.reproducible_flavors) row += "|" row += "-" @@ -308,7 +308,7 @@ def sorting_function(files: frozenset[str]) -> tuple[int, str]: rows += row if len(self._diff_parser.reproducible_flavors) < len( - self._diff_parser.expected_falvors + self._diff_parser.expected_flavors ): rows += "\n*To add affected files to the whitelist, edit `src/gardenlinux/features/reproducibility/nightly_whitelist.json` in python-gardenlinux-lib*\n" diff --git a/src/gardenlinux/features/versioned_flavor.py b/src/gardenlinux/features/versioned_flavor.py new file mode 100644 index 00000000..e026a8ea --- /dev/null +++ b/src/gardenlinux/features/versioned_flavor.py @@ -0,0 +1,97 @@ +# -*- coding: utf-8 -*- + +""" +Garden Linux versioned flavor +""" + +from typing import Optional, Self + +from .flavor import Flavor + + +class VersionedFlavor(Flavor): + """ + Class to represent a Garden Linux versioned flavor. + + :author: Garden Linux Maintainers + :copyright: Copyright 2026 SAP SE + :package: gardenlinux + :subpackage: features + :since: 1.0.0 + :license: https://www.apache.org/licenses/LICENSE-2.0 + Apache License, Version 2.0 + """ + + def __init__( + self, + flavor: str, + arch: str, + version: str, + ): + """ + Constructor __init__(VersionedFlavor) + + :param cname: CName to represent + :param arch: Architecture + :param commit_hash: Commit ID or hash + :param version: Version + + :since: 1.0.0 + """ + + Flavor.__init__(self, flavor, arch) + + self._version = version + + @property + def version(self) -> str: + """ + Returns the version. + + :return: (str) Version + :since: 0.7.0 + """ + + return self._version + + @property + def version_epoch(self) -> Optional[int]: + """ + Returns the Garden Linux version epoch. + + :return: (str) Garden Linux version epoch + :since: 1.0.0 + """ + + epoch = None + + if self._version is not None and "." in self._version: + epoch = int(self._version.split(".", 1)[0]) + + return epoch + + def __str__(self) -> str: + """ + Returns the Garden Linux versioned flavor. + + :return: (str) Returns the Garden Linux versioned flavor + :since: 1.0.0 + """ + + flavor = Flavor.__str__(self) + flavor += f"-{self.version}" + + return flavor + + def _copy_from_instance(self, versioned_flavor: Self) -> None: + """ + Copies values from a given Garden Linux versioned flavor instance. + + :param cname_object: Garden Linux versioned flavor instance + + :since: 1.0.0 + """ + + Flavor._copy_from_instance(self, versioned_flavor) + + self._version = versioned_flavor.version diff --git a/src/gardenlinux/flavors/parser.py b/src/gardenlinux/flavors/parser.py index 08d6e3e6..39e1ebf9 100644 --- a/src/gardenlinux/flavors/parser.py +++ b/src/gardenlinux/flavors/parser.py @@ -12,6 +12,7 @@ from jsonschema import validate as jsonschema_validate from ..constants import GL_FLAVORS_SCHEMA +from ..features import Parser as FeaturesParser from ..logger import LoggerSetup @@ -48,7 +49,9 @@ def __init__(self, data: str, logger: Optional[Logger] = None): self._logger = logger self._logger.debug( - "flavors.Parser initialized with data: {0!r}".format(flavors_data) + "gardenlinux.flavors.Parser initialized with data: {0!r}".format( + flavors_data + ) ) def filter( @@ -111,13 +114,10 @@ def filter( continue # Process features - formatted_features = f"-{'-'.join(features)}" if features else "" + cname = FeaturesParser.get_cname_from_feature_set([name] + features) # Construct the combination - combination = f"{name}-{formatted_features}-{arch}" - - # Format the combination to clean up "--" and "-_" - combination = combination.replace("--", "-").replace("-_", "_") + combination = f"{cname}-{arch}" # Exclude combinations explicitly if Parser.should_exclude(combination, [], wildcard_excludes): diff --git a/src/gardenlinux/git/repository.py b/src/gardenlinux/git/repository.py index dba8d2d3..cbe5ce52 100755 --- a/src/gardenlinux/git/repository.py +++ b/src/gardenlinux/git/repository.py @@ -92,7 +92,9 @@ def root(self) -> Path: except Exception as exc: self._logger.warning(f"Failed to inspect Git directory: {exc}") - self._logger.debug(f"Git root directory: {root_dir}") + self._logger.debug( + f"gardenlinux.git.Repository.root(): Git root directory: {root_dir}" + ) return Path(root_dir) @property diff --git a/src/gardenlinux/github/release/__main__.py b/src/gardenlinux/github/release/__main__.py index b18c5440..a1b97dff 100644 --- a/src/gardenlinux/github/release/__main__.py +++ b/src/gardenlinux/github/release/__main__.py @@ -1,5 +1,6 @@ import argparse import logging +from pathlib import Path from gardenlinux.constants import GARDENLINUX_GITHUB_RELEASE_BUCKET_NAME from gardenlinux.logger import LoggerSetup @@ -127,20 +128,21 @@ def get_parser() -> argparse.ArgumentParser: ) upload_parser.add_argument( - "--release_id", + "--release-id", required=True, help="GitHub release ID to upload the file to (required).", ) upload_parser.add_argument( - "--file_path", + "--file", + type=Path, required=True, help="Path to the file to upload (required).", ) upload_parser.add_argument( "--dry-run", - action="store_true", + action=argparse.BooleanOptionalAction, default=False, help="Perform a dry run without actually uploading the file.", ) @@ -190,11 +192,9 @@ def main() -> None: if args.dry_run: print("Dry Run ...") - print( - f"The file {args.file_path} would be uploaded for release: {release.name}" - ) + print(f"The file {args.file} would be uploaded for release: {release.name}") else: - release.upload_asset(args.file_path, args.overwrite_same_name) + release.upload_asset(args.file, args.overwrite_same_name) else: parser.print_help() diff --git a/src/gardenlinux/github/release/release_images_metadata.py b/src/gardenlinux/github/release/release_images_metadata.py index e1446374..8a55abdb 100644 --- a/src/gardenlinux/github/release/release_images_metadata.py +++ b/src/gardenlinux/github/release/release_images_metadata.py @@ -18,7 +18,7 @@ from ...apt import DebsrcFile from ...constants import GL_DEB_REPO_BASE_URL, GLVD_BASE_URL, REQUESTS_TIMEOUTS -from ...features import CName +from ...features import ArtifactBaseName from ...flavors import Parser from ...git import Repository from ...logger import LoggerSetup @@ -150,34 +150,31 @@ def grouped_flavors_metadata( with TemporaryDirectory() as tmpdir: for flavor in flavors: self._logger.debug( - f"{flavor=} version={self._version} commitish={self._commitish}" + f"gardenlinux.github.release.ReleaseImagesMetadata.grouped_flavors_metadata(): {flavor=} version={self._version} commitish={self._commitish}" ) - cname = CName( - flavor[1], - arch=flavor[0], - commit_hash=self._commitish, - version=self._version, + abn_object = ArtifactBaseName( + f"{flavor[1]}-{self._version}-{self._commitish}" ) try: release_object = list( s3_artifacts.bucket.objects.filter( - Prefix=f"meta/singles/{cname.cname}" + Prefix=f"meta/singles/{abn_object}" ) )[0] s3_artifacts.bucket.download_file( release_object.key, - str(Path(tmpdir, f"{cname.cname}.s3_metadata.yaml")), + str(Path(tmpdir, f"{abn_object}.s3_metadata.yaml")), ) except IndexError: self._logger.warning( - f"No artifacts found for flavor {cname.cname}, skipping..." + f"No artifacts found for flavor {abn_object}, skipping..." ) continue - with Path(tmpdir, f"{cname.cname}.s3_metadata.yaml").open("r") as file: + with Path(tmpdir, f"{abn_object}.s3_metadata.yaml").open("r") as file: s3_data = ReleaseImagesMetadata.parse_s3_metadata( yaml.load(file, Loader=yaml.SafeLoader) ) diff --git a/src/gardenlinux/oci/__init__.py b/src/gardenlinux/oci/__init__.py index 35ab1a4e..99883854 100644 --- a/src/gardenlinux/oci/__init__.py +++ b/src/gardenlinux/oci/__init__.py @@ -4,7 +4,6 @@ OCI module """ -from .container import Container from .image import Image from .image_manifest import ImageManifest from .index import Index @@ -12,9 +11,9 @@ from .manifest import Manifest from .podman import Podman from .podman_context import PodmanContext +from .repository import Repository __all__ = [ - "Container", "ImageManifest", "Image", "Index", @@ -22,4 +21,5 @@ "Manifest", "Podman", "PodmanContext", + "Repository", ] diff --git a/src/gardenlinux/oci/__main__.py b/src/gardenlinux/oci/__main__.py index f0edf08d..506e8aea 100755 --- a/src/gardenlinux/oci/__main__.py +++ b/src/gardenlinux/oci/__main__.py @@ -4,636 +4,601 @@ gl-oci main entrypoint """ +import argparse import json -from typing import List +from pathlib import Path +from typing import Optional -import click - -from .container import Container from .image_manifest import ImageManifest from .podman import Podman from .podman_context import PodmanContext +from .repository import Repository -@click.group() -def cli() -> None: +def _add_additional_tag_list_to_parser(parser: argparse.ArgumentParser) -> None: """ - gl-oci provides functionality to handle OCI containers. It can pull and push - images from remote repositories as well as handle GardenLinux artifacts, OCI - image indices and manifests. + Add `--additional-tag` to the given argument parser. - :since: 0.7.0 + :param parser: ArgumentParser instance + + :since: 1.0.0 """ - pass - - -@cli.command() -@click.option( - "--index", - required=True, - help="OCI image index", -) -@click.option( - "--index-tag", - required=True, - help="OCI image index tag", -) -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=True, - help="OCI tag of image", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the index with", -) -def add_container_to_index( - index: str, - index_tag: str, - container: str, - tag: str, - insecure: bool, - additional_tag: List[str], -) -> None: + parser.add_argument( + "--additional-tag", + action="append", + default=[], + dest="additional_tag", + help="Additional tag to push", + ) + + +def _add_arch_to_parser(parser: argparse.ArgumentParser) -> None: """ - Adds an image container to an OCI image index. + Add `--arch` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - manifest_container = Container(f"{container}:{tag}", insecure=insecure) - - manifest = manifest_container.read_manifest() - - index_resource = Container(f"{index}:{index_tag}", insecure=insecure) - - image_index = index_resource.read_or_generate_index() - image_index.append_manifest(manifest) - - index_resource.push_index(image_index) - index_resource.push_index_for_tags(image_index, additional_tag) - - -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=True, - help="OCI tag of image", -) -@click.option( - "--dir", - "directory", - required=True, - type=click.Path(), - help="Path to the build Containerfile", -) -@click.option( - "--platform", - required=False, - help="OCI platform as os/arch/variant", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the manifest with", -) -@click.option( - "--build_arg", - required=False, - default=[], - multiple=True, - help="Additional build args for Containerfile", -) -@click.option( - "--oci_archive", - required=False, - help="Write build result to the OCI archive path and file name", -) -def build_container( - container: str, - tag: str, - directory: str, - platform: str, - additional_tag: List[str], - build_arg: List[str], - oci_archive: str, -) -> None: + parser.add_argument( + "--arch", + required=False, + dest="arch", + help="Target image CPU architecture", + ) + + +def _add_build_arg_to_parser(parser: argparse.ArgumentParser) -> None: """ - Build an OCI container based on the defined `Containerfile`. + Add `--build-arg` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - podman = Podman() + parser.add_argument( + "--build-arg", + action="append", + default=[], + dest="build_arg", + help="Additional build args for Containerfile", + ) - with PodmanContext() as podman_context: - if oci_archive is None: - image_id = podman.build( - directory, - podman=podman_context, - platform=platform, - oci_tag=f"{container}:{tag}", - build_args=Podman.parse_build_args_list(build_arg), - ) - else: - build_result_data = podman.build_and_save_oci_archive( - directory, - oci_archive, - podman=podman_context, - platform=platform, - oci_tag=f"{container}:{tag}", - build_args=Podman.parse_build_args_list(build_arg), - ) - _, image_id = build_result_data.popitem() +def _add_cname_to_parser(parser: argparse.ArgumentParser) -> None: + """ + Add `--cname` to the given argument parser. - if additional_tag is not None: - podman.tag_list( - image_id, Podman.get_container_tag_list(container, additional_tag) - ) + :param parser: ArgumentParser instance + + :since: 1.0.0 + """ - print(image_id) + parser.add_argument( + "--cname", + required=True, + dest="cname", + help="Garden Linux Canonical Name", + ) -@cli.command() -@click.option( - "--oci_archive", - required=False, - help="Write build result to the OCI archive path and file name", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the manifest with", -) -def load_container(oci_archive: str, additional_tag: List[str]) -> None: +def _add_commit_to_parser(parser: argparse.ArgumentParser) -> None: """ - Load an OCI archive. + Add `--commit` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - podman = Podman() + parser.add_argument( + "--commit", + required=False, + dest="commit", + help="Commit ID or hash", + ) + + +def _add_cosign_file_to_parser(parser: argparse.ArgumentParser) -> None: + """ + Add `--cosign-file` to the given argument parser. + + :param parser: ArgumentParser instance + + :since: 1.0.0 + """ + + parser.add_argument( + "--cosign-file", + type=Path, + required=False, + dest="cosign_file", + help="A file where pushed manifests digests is written to.", + ) + + +def _add_dir_to_parser( + parser: argparse.ArgumentParser, help_text: str, default_value: Optional[str] = None +) -> None: + """ + Add `--dir` to the given argument parser. - with PodmanContext() as podman_context: - image_id = podman.load_oci_archive(oci_archive, podman=podman_context) + :param parser: ArgumentParser instance - if additional_tag is not None: - podman.tag_list(image_id, additional_tag, podman=podman_context) + :since: 1.0.0 + """ - print(image_id) + parser.add_argument( + "--dir", + type=Path, + required=(default_value is None), + default=default_value, + dest="directory", + help=help_text, + ) -@cli.command() -@click.option( - "--dir", - "directory", - required=True, - type=click.Path(), - help="path to the build artifacts", -) -def load_containers_from_directory(directory: str) -> None: +def _add_manifest_file_to_parser(parser: argparse.ArgumentParser) -> None: """ - Load multiple OCI archives. + Add `--manifest-file` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - result = Podman().load_oci_archives_from_directory(directory) - print(json.dumps(result)) - - -@cli.command() -@click.option( - "--index", - required=True, - help="OCI image index", -) -@click.option( - "--index-tag", - required=True, - help="OCI image index tag", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the index with", -) -def new_index( - index: str, index_tag: str, insecure: bool, additional_tag: List[str] + parser.add_argument( + "--manifest-file", + type=Path, + default="manifests/manifest.json", + dest="manifest_file", + help="A file where the metadata for the pushed manifest is written to.", + ) + + +def _add_oci_archive_to_parser( + parser: argparse.ArgumentParser, required: bool = True ) -> None: """ - Create a new OCI image index. + Add `--oci-archive` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - index_resource = Container(f"{index}:{index_tag}", insecure=insecure) - - image_index = index_resource.generate_index() - index_resource.push_index(image_index) - index_resource.push_index_for_tags(image_index, additional_tag) - - -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=False, - help="OCI tag of image", -) -@click.option( - "--platform", - required=False, - help="OCI platform as os/arch/variant", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -def pull_container(container: str, tag: str, platform: str, insecure: bool) -> None: - """ - Pull an OCI image container from a remote OCI registry. + parser.add_argument( + "--oci-archive", + type=Path, + required=required, + dest="oci_archive", + help="OCI archive path and file name", + ) + + +def _add_oci_destination_to_parser(parser: argparse.ArgumentParser) -> None: + """ + Add `--destination` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - image_id = Podman(insecure=insecure).pull(container, oci_tag=tag, platform=platform) - print(image_id) - - -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=False, - help="OCI tag of image", -) -@click.option( - "--destination", - required=False, - help="OCI container destination", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -def push_container(container: str, tag: str, destination: str, insecure: bool) -> None: - """ - Push an OCI image container to a remote OCI registry. + parser.add_argument( + "--destination", + required=False, + dest="destination", + help="OCI repository destination", + ) + + +def _add_oci_index_args_to_parser(parser: argparse.ArgumentParser) -> None: + """ + Add `--index and --index-tag` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - Podman(insecure=insecure).push(container, oci_tag=tag, destination=destination) - - -@cli.command() -@click.option( - "--index", - required=True, - help="OCI image index", -) -@click.option( - "--index-tag", - required=True, - help="OCI image index tag", -) -@click.option( - "--manifest_folder", - default="manifests", - help="A folder where the index entries are read from.", -) -@click.option( - "--insecure", - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the index with", -) -def push_index_from_directory( - index: str, - index_tag: str, - manifest_folder: str, - insecure: bool, - additional_tag: List[str], -) -> None: + parser.add_argument( + "--index", + required=True, + dest="index", + help="OCI image index", + ) + + parser.add_argument( + "--index-tag", + required=True, + dest="index_tag", + help="OCI image index tag", + ) + + +def _add_oci_insecure_to_parser(parser: argparse.ArgumentParser) -> None: """ - Pushes manifests stored in a directory to a given OCI image index. - - :since: 0.10.9 - """ - - index_resource = Container(f"{index}:{index_tag}", insecure=insecure) - index_resource.push_index_from_directory(manifest_folder, additional_tag) - - -@cli.command() -@click.option( - "--index", - required=True, - help="OCI image index", -) -@click.option( - "--index-tag", - required=True, - help="OCI image index tag", -) -@click.option( - "--insecure", - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--tag", - required=True, - multiple=True, - help="Tag to push the OCI image index with", -) -def push_index_tags(index: str, index_tag: str, insecure: bool, tag: List[str]) -> None: - """ - Push OCI image index tags to a registry. - - :since: 0.10.9 - """ - - index_resource = Container(f"{index}:{index_tag}", insecure=insecure) - - image_index = index_resource.read_or_generate_index() - index_resource.push_index_for_tags(image_index, tag) - - -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option("--cname", required=True, help="Canonical Name of Image") -@click.option( - "--arch", - required=False, - default=None, - help="Target Image CPU Architecture", -) -@click.option( - "--version", - required=False, - default=None, - help="Version of image", -) -@click.option( - "--commit", - required=False, - default=None, - help="Commit of image", -) -@click.option( - "--dir", - "directory", - required=True, - type=click.Path(), - help="path to the build artifacts", -) -@click.option( - "--cosign_file", - required=False, - help="A file where the pushed manifests digests is written to. The content can be used by an external tool (e.g. cosign) to sign the manifests contents", -) -@click.option( - "--manifest_file", - type=click.Path(), - default="manifests/manifest.json", - help="A file where the index entry for the pushed manifest is written to.", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the manifest with", -) -def push_manifest( - container: str, - cname: str, - arch: str, - version: str, - commit: str, - directory: str, - cosign_file: str, - manifest_file: str, - insecure: bool, - additional_tag: List[str], + Add `--insecure` to the given argument parser. + + :param parser: ArgumentParser instance + + :since: 1.0.0 + """ + + parser.add_argument( + "--insecure", + action=argparse.BooleanOptionalAction, + dest="insecure", + default=False, + help="Use HTTP to communicate with the registry", + ) + + +def _add_oci_platform_to_parser( + parser: argparse.ArgumentParser, required: bool = True ) -> None: """ - Push to an OCI image container given GardenLinux canonical named artifacts - in a specified directory. + Add `--platform` to the given argument parser. - :since: 0.7.0 + :param parser: ArgumentParser instance + + :since: 1.0.0 """ - container = Container(f"{container}:{version}", insecure=insecure) + parser.add_argument( + "--platform", + required=required, + dest="platform", + help="OCI platform as os/arch/variant", + ) + + +def _add_oci_repository_to_parser(parser: argparse.ArgumentParser) -> None: + """ + Add `--repository` to the given argument parser. - manifest = container.read_or_generate_manifest(cname, arch, version, commit) + :param parser: ArgumentParser instance - if not isinstance(manifest, ImageManifest): - raise RuntimeError("Data given for OCI image manifest is incomplete") + :since: 1.0.0 + """ - container.push_manifest_and_artifacts_from_directory( - manifest, directory, manifest_file, additional_tag + parser.add_argument( + "--repository", + required=True, + dest="repository", + help="Repository path", ) - if cosign_file: - print(manifest.digest, file=open(cosign_file, "w")) - - -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--cname", - required=False, - default=None, - help="Canonical Name of Image", -) -@click.option( - "--arch", - required=False, - default=None, - help="Target Image CPU Architecture", -) -@click.option( - "--version", - required=False, - default=None, - help="Version of image", -) -@click.option( - "--commit", - required=False, - default=None, - help="Commit of image", -) -@click.option( - "--insecure", - type=bool, - default=False, - help="Use HTTP to communicate with the registry", -) -@click.option( - "--tag", - required=True, - multiple=True, - help="Tag to push the manifest with", -) -def push_manifest_tags( - container: str, - cname: str, - arch: str, - version: str, - commit: str, - insecure: bool, - tag: List[str], + +def _add_oci_tag_to_parser( + parser: argparse.ArgumentParser, + required: bool = True, + multiple: bool = False, ) -> None: """ - Push tags to an OCI image container for a given GardenLinux canonical named image. + Add `--tag` to the given argument parser. + + :param parser: ArgumentParser instance - :since: 0.10.0 + :since: 1.0.0 """ - container = Container(f"{container}:{version}", insecure=insecure) + kwargs = { + "required": required, + "dest": "tag", + "help": "OCI tag of image", + } - manifest = container.read_or_generate_manifest(cname, arch, version, commit) - container.push_manifest_for_tags(manifest, tag) + if multiple: + kwargs["action"] = "append" + kwargs["default"] = [] + parser.add_argument("--tag", **kwargs) # type: ignore[arg-type] -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=False, - help="OCI tag of image", -) -@click.option( - "--oci_archive", - required=False, - help="Write build result to the OCI archive path and file name", -) -def save_container(container: str, tag: str, oci_archive: str) -> None: + +def _add_version_to_parser(parser: argparse.ArgumentParser) -> None: """ - Saves a given OCI image container as an OCI archive. + Add `--version` to the given argument parser. + + :param parser: ArgumentParser instance :since: 1.0.0 """ - podman = Podman() - - image_id = podman.get_image_id(container, oci_tag=tag) - podman.save_oci_archive(image_id, oci_archive, oci_tag=tag) + parser.add_argument( + "--version", + required=False, + dest="version", + help="Version of image", + ) -@cli.command() -@click.option( - "--container", - required=True, - help="Container Name", -) -@click.option( - "--tag", - required=False, - help="OCI tag of image", -) -@click.option( - "--additional_tag", - required=False, - multiple=True, - help="Additional tag to push the manifest with", -) -def tag_container(container: str, tag: str, additional_tag: List[str]) -> None: +def get_parser() -> argparse.ArgumentParser: """ - Adds additional tags to a given OCI image container. + Get the argument parser for gl-oci. + Used for documentation generation. + :return: ArgumentParser instance :since: 1.0.0 """ - podman = Podman() + parser = argparse.ArgumentParser( + prog="gl-oci", + description="gl-oci provides functionality to handle OCI images.", + ) - with PodmanContext() as podman_context: - image_id = podman.get_image_id(container, podman=podman_context, oci_tag=tag) + subparsers = parser.add_subparsers(dest="action", help="Action to perform.") - if additional_tag is not None: - podman.tag_list( - image_id, - Podman.get_container_tag_list(container, additional_tag), - podman=podman_context, - ) + add_image_to_index_parser = subparsers.add_parser("add-image-to-index") + + _add_oci_index_args_to_parser(add_image_to_index_parser) + _add_oci_repository_to_parser(add_image_to_index_parser) + _add_oci_tag_to_parser(add_image_to_index_parser) + _add_oci_insecure_to_parser(add_image_to_index_parser) + _add_additional_tag_list_to_parser(add_image_to_index_parser) + + build_image_parser = subparsers.add_parser("build-image") + + _add_oci_repository_to_parser(build_image_parser) + _add_oci_tag_to_parser(build_image_parser) + _add_dir_to_parser(build_image_parser, "Path to the build Containerfile") + _add_oci_platform_to_parser(build_image_parser, False) + _add_additional_tag_list_to_parser(build_image_parser) + _add_build_arg_to_parser(build_image_parser) + _add_oci_archive_to_parser(build_image_parser, False) + + load_image_parser = subparsers.add_parser("load-image") + + _add_oci_archive_to_parser(load_image_parser, False) + _add_additional_tag_list_to_parser(load_image_parser) + + load_images_from_directory_parser = subparsers.add_parser( + "load-images-from-directory" + ) + + _add_dir_to_parser( + load_images_from_directory_parser, "Directory of the build artifacts" + ) + + new_index_parser = subparsers.add_parser("new-index") + + _add_oci_index_args_to_parser(new_index_parser) + _add_oci_insecure_to_parser(new_index_parser) + _add_additional_tag_list_to_parser(new_index_parser) + + pull_image_parser = subparsers.add_parser("pull-image") + + _add_oci_repository_to_parser(pull_image_parser) + _add_oci_tag_to_parser(pull_image_parser, False) + _add_oci_platform_to_parser(pull_image_parser, False) + _add_oci_insecure_to_parser(pull_image_parser) + + push_image_parser = subparsers.add_parser("push-image") + + _add_oci_repository_to_parser(push_image_parser) + _add_oci_tag_to_parser(push_image_parser, False) + _add_oci_destination_to_parser(push_image_parser) + _add_oci_insecure_to_parser(push_image_parser) + + push_index_from_directory_parser = subparsers.add_parser( + "push-index-from-directory" + ) + + _add_oci_index_args_to_parser(push_index_from_directory_parser) + + _add_dir_to_parser( + push_index_from_directory_parser, + default_value="manifests", + help_text="Directory to read index entry files from.", + ) + + _add_oci_insecure_to_parser(push_index_from_directory_parser) + _add_additional_tag_list_to_parser(push_index_from_directory_parser) + + push_index_tags_parser = subparsers.add_parser("push-index-tags") + + _add_oci_index_args_to_parser(push_index_tags_parser) + _add_oci_insecure_to_parser(push_index_tags_parser) + _add_oci_tag_to_parser(push_index_tags_parser, multiple=True) + + push_manifest_parser = subparsers.add_parser("push-manifest") + + _add_oci_repository_to_parser(push_manifest_parser) + _add_cname_to_parser(push_manifest_parser) + _add_arch_to_parser(push_manifest_parser) + _add_version_to_parser(push_manifest_parser) + _add_commit_to_parser(push_manifest_parser) + _add_dir_to_parser(push_manifest_parser, "Directory of the build artifacts") + _add_manifest_file_to_parser(push_manifest_parser) + _add_cosign_file_to_parser(push_manifest_parser) + _add_oci_insecure_to_parser(push_manifest_parser) + _add_additional_tag_list_to_parser(push_manifest_parser) + + push_manifest_tags_parser = subparsers.add_parser("push-manifest-tags") + + _add_oci_repository_to_parser(push_manifest_tags_parser) + _add_cname_to_parser(push_manifest_tags_parser) + _add_arch_to_parser(push_manifest_tags_parser) + _add_version_to_parser(push_manifest_tags_parser) + _add_commit_to_parser(push_manifest_tags_parser) + _add_oci_insecure_to_parser(push_manifest_tags_parser) + _add_oci_tag_to_parser(push_manifest_tags_parser, multiple=True) + + save_image_parser = subparsers.add_parser("save-image") + + _add_oci_repository_to_parser(save_image_parser) + _add_oci_tag_to_parser(save_image_parser, False) + _add_oci_archive_to_parser(save_image_parser, False) + + tag_image_parser = subparsers.add_parser("tag-image") + + _add_oci_repository_to_parser(tag_image_parser) + _add_oci_tag_to_parser(tag_image_parser, False) + _add_additional_tag_list_to_parser(tag_image_parser) + + return parser def main() -> None: """ - gl-oci main() + gl-oci provides functionality to handle OCI images. It can pull and push + images from remote repositories as well as handle GardenLinux artifacts, OCI + image indices and manifests. :since: 0.7.0 """ - cli() + parser = get_parser() + args = parser.parse_args() + + match args.action: + case "add-image-to-index": + manifest_repository = Repository( + f"{args.repository}:{args.tag}", insecure=args.insecure + ) + + manifest = manifest_repository.read_manifest() + + index_resource = Repository( + f"{args.index}:{args.index_tag}", insecure=args.insecure + ) + + image_index = index_resource.read_or_generate_index() + image_index.append_manifest(manifest) + + index_resource.push_index(image_index) + index_resource.push_index_for_tags(image_index, args.additional_tag) + case "build-image": + podman = Podman() + + with PodmanContext() as podman_context: + if args.oci_archive is None: + image_id = podman.build( + args.directory, + podman=podman_context, + platform=args.platform, + oci_tag=f"{args.repository}:{args.tag}", + build_args=Podman.parse_build_args_list(args.build_arg), + ) + else: + build_result_data = podman.build_and_save_oci_archive( + args.directory, + args.oci_archive, + podman=podman_context, + platform=args.platform, + oci_tag=f"{args.repository}:{args.tag}", + build_args=Podman.parse_build_args_list(args.build_arg), + ) + + _, image_id = build_result_data.popitem() + + if args.additional_tag is not None: + podman.tag_list( + image_id, + Podman.get_image_tag_list(args.repository, args.additional_tag), + ) + + print(image_id) + case "load-image": + podman = Podman() + + with PodmanContext() as podman_context: + image_id = podman.load_oci_archive( + args.oci_archive, podman=podman_context + ) + + if args.additional_tag is not None: + podman.tag_list( + image_id, args.additional_tag, podman=podman_context + ) + + print(image_id) + case "load-images-from-directory": + result = Podman().load_oci_archives_from_directory(args.directory) + print(json.dumps(result)) + case "new-index": + index_resource = Repository( + f"{args.index}:{args.index_tag}", insecure=args.insecure + ) + + image_index = index_resource.generate_index() + index_resource.push_index(image_index) + index_resource.push_index_for_tags(image_index, args.additional_tag) + case "pull-image": + image_id = Podman(insecure=args.insecure).pull( + args.repository, oci_tag=args.tag, platform=args.platform + ) + print(image_id) + case "push-image": + Podman(insecure=args.insecure).push( + args.repository, oci_tag=args.tag, destination=args.destination + ) + case "push-index-from-directory": + index_resource = Repository( + f"{args.index}:{args.index_tag}", insecure=args.insecure + ) + index_resource.push_index_from_directory( + args.directory, args.additional_tag + ) + case "push-index-tags": + index_resource = Repository( + f"{args.index}:{args.index_tag}", insecure=args.insecure + ) + + image_index = index_resource.read_or_generate_index() + index_resource.push_index_for_tags(image_index, args.tag) + case "push-manifest": + repository = Repository( + f"{args.repository}:{args.version}", insecure=args.insecure + ) + + manifest = repository.read_or_generate_manifest( + args.cname, args.arch, args.version, args.commit + ) + + if not isinstance(manifest, ImageManifest): + raise RuntimeError("Data given for OCI image manifest is incomplete") + + repository.push_manifest_and_artifacts_from_directory( + manifest, args.directory, args.manifest_file, args.additional_tag + ) + + if args.cosign_file: + print(manifest.digest, file=open(args.cosign_file, "w")) + case "push-manifest-tags": + repository = Repository( + f"{args.repository}:{args.version}", insecure=args.insecure + ) + + manifest = repository.read_or_generate_manifest( + args.cname, args.arch, args.version, args.commit + ) + + repository.push_manifest_for_tags(manifest, args.tag) + case "save-image": + podman = Podman() + + image_id = podman.get_image_id(args.repository, oci_tag=args.tag) + podman.save_oci_archive(image_id, args.oci_archive, oci_tag=args.tag) + case "tag-image": + podman = Podman() + + with PodmanContext() as podman_context: + image_id = podman.get_image_id( + args.repository, podman=podman_context, oci_tag=args.tag + ) + + if args.additional_tag is not None: + podman.tag_list( + image_id, + Podman.get_image_tag_list(args.repository, args.additional_tag), + podman=podman_context, + ) if __name__ == "__main__": - cli() + main() diff --git a/src/gardenlinux/oci/image_manifest.py b/src/gardenlinux/oci/image_manifest.py index 324c16c8..2e0a5e5c 100644 --- a/src/gardenlinux/oci/image_manifest.py +++ b/src/gardenlinux/oci/image_manifest.py @@ -13,7 +13,7 @@ from oras.defaults import annotation_title as ANNOTATION_TITLE from ..constants import GL_DISTRIBUTION_NAME, GL_REPOSITORY_URL -from ..features import CName +from ..features import Flavor from .layer import Layer from .manifest import Manifest from .platform import new_platform @@ -37,26 +37,42 @@ class ImageManifest(Manifest): """ OCI image manifest architecture annotation """ - ANNOTATION_CNAME_KEY = "cname" + ANNOTATION_CNAME_KEY = "io.gardenlinux.image.cname" """ - OCI image manifest GardenLinux canonical name annotation + OCI image manifest Garden Linux canonical name annotation + """ + ANNOTATION_CNAME_DEPRECATED_KEY = "cname" + """ + OCI image manifest Garden Linux canonical name deprecated annotation + """ + ANNOTATION_COMMIT_KEY = "org.opencontainers.image.revision" + """ + OCI image manifest GardenLinux commit hash annotation """ ANNOTATION_DESCRIPTION_KEY = "org.opencontainers.image.description" """ OCI image manifest description annotation """ - ANNOTATION_FEATURE_SET_KEY = "feature_set" + ANNOTATION_FEATURE_SET_KEY = "io.gardenlinux.image.feature-set" + """ + OCI image manifest Garden Linux feature set annotation + """ + ANNOTATION_FEATURE_SET_DEPRECATED_KEY = "feature_set" """ - OCI image manifest GardenLinux feature set annotation + OCI image manifest Garden Linux feature set deprecated annotation """ ANNOTATION_SOURCE_REPO_KEY = "org.opencontainers.image.source" """ - OCI image manifest GardenLinux source repository URL annotation + OCI image manifest Garden Linux source repository URL annotation """ ANNOTATION_TITLE_KEY = ANNOTATION_TITLE """ OCI image manifest title annotation """ + ANNOTATION_VERSION_KEY = "org.opencontainers.image.version" + """ + OCI image manifest GardenLinux version annotation + """ @property def arch(self) -> str: @@ -90,9 +106,9 @@ def arch(self, value: str) -> None: @property def cname(self) -> str: """ - Returns the GardenLinux canonical name of the OCI image manifest. + Returns the Garden Linux canonical name of the OCI image manifest. - :return: (str) OCI image GardenLinux canonical name + :return: (str) OCI image Garden Linux canonical name :since: 0.7.0 """ @@ -106,9 +122,9 @@ def cname(self) -> str: @cname.setter def cname(self, value: str) -> None: """ - Sets the GardenLinux canonical name of the OCI image manifest. + Sets the Garden Linux canonical name of the OCI image manifest. - :param value: OCI image GardenLinux canonical name + :param value: OCI image Garden Linux canonical name :since: 0.7.0 """ @@ -119,9 +135,9 @@ def cname(self, value: str) -> None: @property def feature_set(self) -> str: """ - Returns the GardenLinux feature set of the OCI image manifest. + Returns the Garden Linux feature set of the OCI image manifest. - :return: (str) OCI image GardenLinux feature set + :return: (str) OCI image Garden Linux feature set :since: 0.7.0 """ @@ -135,9 +151,9 @@ def feature_set(self) -> str: @feature_set.setter def feature_set(self, value: str) -> None: """ - Sets the GardenLinux feature set of the OCI image manifest. + Sets the Garden Linux feature set of the OCI image manifest. - :param value: OCI image GardenLinux feature set + :param value: OCI image Garden Linux feature set :since: 0.7.0 """ @@ -148,13 +164,32 @@ def feature_set(self, value: str) -> None: @property def flavor(self) -> str: """ - Returns the GardenLinux flavor of the OCI image manifest. + Returns the Garden Linux flavor of the OCI image manifest. - :return: (str) OCI image GardenLinux flavor + :return: (str) OCI image Garden Linux flavor :since: 0.7.0 """ - return CName(self.cname).flavor + return Flavor(self.cname, self.arch).flavor + + @flavor.setter + def flavor(self, value: str) -> None: + """ + Sets the Garden Linux flavor of the OCI image manifest. + + :param value: OCI image Garden Linux flavor + + :since: 1.0.0 + """ + + self._ensure_annotations_dict() + + if "-" not in value: + raise RuntimeError(f"Garden Linux flavor is invalid: {value}") + + cname, arch = value.rsplit("-", 1) + self["annotations"][ImageManifest.ANNOTATION_ARCH_KEY] = arch + self["annotations"][ImageManifest.ANNOTATION_CNAME_KEY] = cname @property def extended_dict(self) -> Dict[str, Any]: @@ -165,7 +200,7 @@ def extended_dict(self) -> Dict[str, Any]: :since: 1.0.0 """ - manifest_dict = Manifest(self).extended_dict + manifest_dict: Dict[str, Any] = Manifest.extended_dict.fget(self) # type: ignore[attr-defined] manifest_annotations = manifest_dict["annotations"] if ImageManifest.ANNOTATION_TITLE_KEY not in manifest_annotations: @@ -185,11 +220,11 @@ def extended_dict(self) -> Dict[str, Any]: manifest_description += f" ({self.arch})" if ImageManifest.ANNOTATION_VERSION_KEY in manifest_annotations: - manifest_annotations["org.opencontainers.image.version"] = self.version + manifest_annotations[ImageManifest.ANNOTATION_VERSION_KEY] = self.version manifest_description += " " + self.version if ImageManifest.ANNOTATION_COMMIT_KEY in manifest_annotations: - manifest_annotations["org.opencontainers.image.revision"] = self.commit + manifest_annotations[ImageManifest.ANNOTATION_COMMIT_KEY] = self.commit manifest_description += f" ({self.commit})" if ImageManifest.ANNOTATION_FEATURE_SET_KEY in manifest_annotations: @@ -202,6 +237,20 @@ def extended_dict(self) -> Dict[str, Any]: manifest_description ) + if ( + ImageManifest.ANNOTATION_CNAME_KEY in manifest_annotations + and ImageManifest.ANNOTATION_VERSION_KEY in manifest_annotations + and ImageManifest.ANNOTATION_COMMIT_KEY in manifest_annotations + ): + manifest_annotations[ImageManifest.ANNOTATION_CNAME_DEPRECATED_KEY] = ( + f"{self.flavor}-{self.version}-{self.commit}" + ) + + if ImageManifest.ANNOTATION_FEATURE_SET_KEY in manifest_annotations: + manifest_annotations[ + ImageManifest.ANNOTATION_FEATURE_SET_DEPRECATED_KEY + ] = manifest_annotations[ImageManifest.ANNOTATION_FEATURE_SET_KEY] + return manifest_dict @property diff --git a/src/gardenlinux/oci/manifest.py b/src/gardenlinux/oci/manifest.py index cf42a9dd..a5fba15e 100644 --- a/src/gardenlinux/oci/manifest.py +++ b/src/gardenlinux/oci/manifest.py @@ -26,14 +26,22 @@ class Manifest(dict): # type: ignore[type-arg] Apache License, Version 2.0 """ - ANNOTATION_COMMIT_KEY = "commit" + ANNOTATION_COMMIT_KEY = "io.gardenlinux.manifest.commit" """ OCI image manifest GardenLinux commit hash annotation """ - ANNOTATION_VERSION_KEY = "version" + ANNOTATION_COMMIT_DEPRECATED_KEY = "commit" + """ + OCI image manifest GardenLinux commit hash deprecated annotation + """ + ANNOTATION_VERSION_KEY = "io.gardenlinux.manifest.version" """ OCI image manifest GardenLinux version annotation """ + ANNOTATION_VERSION_DEPRECATED_KEY = "version" + """ + OCI image manifest GardenLinux version deprecated annotation + """ def __init__(self, *args: Any, **kwargs: Any): """ @@ -59,12 +67,14 @@ def commit(self) -> str: :since: 0.7.0 """ - if Manifest.ANNOTATION_COMMIT_KEY not in self.get("annotations", {}): + annotation_commit_key = self.__class__.ANNOTATION_COMMIT_KEY + + if annotation_commit_key not in self.get("annotations", {}): raise RuntimeError( - f"Unexpected manifest with missing config annotation '{Manifest.ANNOTATION_COMMIT_KEY}' found" + f"Unexpected manifest with missing config annotation '{annotation_commit_key}' found" ) - return self["annotations"][Manifest.ANNOTATION_COMMIT_KEY] # type: ignore[no-any-return] + return self["annotations"][annotation_commit_key] # type: ignore[no-any-return] @commit.setter def commit(self, value: str) -> None: @@ -77,7 +87,7 @@ def commit(self, value: str) -> None: """ self._ensure_annotations_dict() - self["annotations"][Manifest.ANNOTATION_COMMIT_KEY] = value + self["annotations"][self.__class__.ANNOTATION_COMMIT_KEY] = value @property def config_json(self) -> bytes: @@ -112,7 +122,24 @@ def extended_dict(self) -> Dict[str, Any]: """ self._ensure_annotations_dict() - return self.copy() + + manifest_dict = self.copy() + manifest_annotations = manifest_dict["annotations"] + + annotation_commit_key = self.__class__.ANNOTATION_COMMIT_KEY + annotation_version_key = self.__class__.ANNOTATION_VERSION_KEY + + if annotation_commit_key in manifest_annotations: + manifest_annotations[Manifest.ANNOTATION_COMMIT_DEPRECATED_KEY] = ( + manifest_annotations[annotation_commit_key] + ) + + if annotation_version_key in manifest_annotations: + manifest_annotations[Manifest.ANNOTATION_VERSION_DEPRECATED_KEY] = ( + manifest_annotations[annotation_version_key] + ) + + return manifest_dict @property def json(self) -> bytes: @@ -145,12 +172,14 @@ def version(self) -> str: :since: 0.7.0 """ - if Manifest.ANNOTATION_VERSION_KEY not in self.get("annotations", {}): + annotation_version_key = self.__class__.ANNOTATION_VERSION_KEY + + if annotation_version_key not in self.get("annotations", {}): raise RuntimeError( - f"Unexpected manifest with missing config annotation '{Manifest.ANNOTATION_VERSION_KEY}' found" + f"Unexpected manifest with missing config annotation '{annotation_version_key}' found" ) - return self["annotations"][Manifest.ANNOTATION_VERSION_KEY] # type: ignore[no-any-return] + return self["annotations"][annotation_version_key] # type: ignore[no-any-return] @version.setter def version(self, value: str) -> None: @@ -163,7 +192,7 @@ def version(self, value: str) -> None: """ self._ensure_annotations_dict() - self["annotations"][Manifest.ANNOTATION_VERSION_KEY] = value + self["annotations"][self.__class__.ANNOTATION_VERSION_KEY] = value def config_from_dict( self, config: Dict[str, Any], annotations: Dict[str, Any] diff --git a/src/gardenlinux/oci/podman.py b/src/gardenlinux/oci/podman.py index 28c585d2..246e4f81 100644 --- a/src/gardenlinux/oci/podman.py +++ b/src/gardenlinux/oci/podman.py @@ -56,7 +56,7 @@ def build( **kwargs: Any, ) -> str: """ - Build a container. + Build a image. :since: 1.0.0 """ @@ -96,7 +96,7 @@ def build_and_save_oci_archive( **kwargs: Any, ) -> Dict[str, str]: """ - Build a container and save the result as an OCI archive with the given path and file name. + Build a image and save the result as an OCI archive with the given path and file name. :since: 1.0.0 """ @@ -119,41 +119,39 @@ def build_and_save_oci_archive( @PodmanContext.wrap def get_image( self, - container: str, + image: str, podman: PodmanContext, oci_tag: Optional[str] = None, ) -> Image: """ - Returns the Podman image ID for a given OCI container tag. + Returns the Podman image ID for a given OCI image tag. :since: 1.0.0 """ - container_tag = container - if oci_tag is not None: if ":" in oci_tag: - container_tag = oci_tag + image = oci_tag else: - container_tag += f":{oci_tag}" + image += f":{oci_tag}" - return Image(podman.images.get(container_tag)) + return Image(podman.images.get(image)) @PodmanContext.wrap def get_image_id( self, - container: str, + image: str, podman: PodmanContext, oci_tag: Optional[str] = None, ) -> str: """ - Returns the Podman image ID for a given OCI container tag. + Returns the Podman image ID for a given OCI image tag. :since: 1.0.0 """ - image = self.get_image(container, oci_tag=oci_tag, podman=podman) - return image.id # type: ignore[no-any-return] + image_object = self.get_image(image, oci_tag=oci_tag, podman=podman) + return image_object.id # type: ignore[no-any-return] @PodmanContext.wrap def load_oci_archive( @@ -195,13 +193,13 @@ def load_oci_archives_from_directory( @PodmanContext.wrap def pull( self, - container: str, + image: str, podman: PodmanContext, platform: Optional[str] = None, oci_tag: Optional[str] = None, ) -> str: """ - Pulls a given OCI container. + Pulls a given OCI image. :since: 1.0.0 """ @@ -217,19 +215,19 @@ def pull( if oci_tag is not None: kwargs["tag"] = oci_tag - image = podman.images.pull(container, **kwargs) - return image.id # type: ignore[no-any-return] + image_object = podman.images.pull(image, **kwargs) + return image_object.id # type: ignore[no-any-return] @PodmanContext.wrap def push( self, - container: str, + image: str, podman: PodmanContext, destination: Optional[str] = None, oci_tag: Optional[str] = None, ) -> None: """ - Pushs a given OCI container. + Pushs a given OCI image. :since: 1.0.0 """ @@ -245,7 +243,7 @@ def push( if oci_tag is not None: kwargs["tag"] = oci_tag - podman.images.push(container, **kwargs) + podman.images.push(image, **kwargs) @PodmanContext.wrap def save_oci_archive( @@ -285,22 +283,22 @@ def save_oci_archive( def tag( self, image_id: str, - oci_container_tag: str, + oci_tag: str, podman: PodmanContext, ) -> None: """ - Tags a given Podman image ID with the container tag given. + Tags a given Podman image ID with the image tag given. :since: 1.0.0 """ - if ":" in oci_container_tag: - oci_data = oci_container_tag.rsplit(":", 1) + if ":" in oci_tag: + oci_data = oci_tag.rsplit(":", 1) if len(oci_data) < 2: raise RuntimeError("No tag given") else: - oci_data = ["", oci_container_tag] + oci_data = ["", oci_tag] image = podman.images.get(image_id) image.tag(oci_data[0], oci_data[1]) @@ -309,36 +307,36 @@ def tag( def tag_list( self, image_id: str, - oci_container_tags_list: List[str], + oci_tags_list: List[str], podman: PodmanContext, ) -> None: """ - Tags a given Podman image ID with the list of container tags given. + Tags a given Podman image ID with the list of image tags given. :since: 1.0.0 """ - for container_tag in oci_container_tags_list: - self.tag(image_id, container_tag, podman=podman) + for oci_tag in oci_tags_list: + self.tag(image_id, oci_tag, podman=podman) @staticmethod - def get_container_tag_list(container: str, tag_list: Sequence[str]) -> List[str]: + def get_image_tag_list(image: str, tag_list: Sequence[str]) -> List[str]: """ - Returns a list of "container:tag" values. + Returns a list of "image:tag" values. :since: 1.0.0 """ - container_tag_list = [] + image_tag_list = [] if isinstance(tag_list, Sequence): for tag in tag_list: if ":" in tag: - container_tag_list.append(tag) + image_tag_list.append(tag) else: - container_tag_list.append(f"{container}:{tag}") + image_tag_list.append(f"{image}:{tag}") - return container_tag_list + return image_tag_list @staticmethod def parse_build_args_list(args_list: List[str]) -> Dict[str, str]: diff --git a/src/gardenlinux/oci/container.py b/src/gardenlinux/oci/repository.py similarity index 79% rename from src/gardenlinux/oci/container.py rename to src/gardenlinux/oci/repository.py index f01195d7..b781335f 100644 --- a/src/gardenlinux/oci/container.py +++ b/src/gardenlinux/oci/repository.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- """ -OCI container +OCI repository """ import json @@ -22,7 +22,7 @@ from requests import HTTPError, Response from ..constants import OCI_IMAGE_INDEX_MEDIA_TYPE -from ..features.cname import CName +from ..features import ArtifactBaseName from ..logger import LoggerSetup from .image_manifest import ImageManifest from .index import Index @@ -31,55 +31,55 @@ from .schemas import index as IndexSchema -class Container(Registry): # type: ignore[misc] +class Repository(Registry): # type: ignore[misc] """ - OCI container instance to provide methods for interaction. + OCI repository instance to provide methods for interaction. :author: Garden Linux Maintainers :copyright: Copyright 2024 SAP SE :package: gardenlinux :subpackage: oci - :since: 0.7.0 + :since: 1.0.0 :license: https://www.apache.org/licenses/LICENSE-2.0 Apache License, Version 2.0 """ def __init__( self, - container_url: str, + repository_url: str, insecure: bool = False, token: Optional[str] = None, logger: Optional[logging.Logger] = None, ): """ - Constructor __init__(Container) + Constructor __init__(Repository) - :param container_url: OCI container URL + :param repository_url: OCI repository URL :param insecure: True if access is provided via HTTP without encryption :param token: OCI access token :param logger: Logger instance - :since: 0.7.0 + :since: 1.0.0 """ - container_data = container_url.rsplit(":", 1) + repository_data = repository_url.rsplit(":", 1) - if len(container_data) < 2: - raise RuntimeError("Container name given is invalid") + if len(repository_data) < 2: + raise RuntimeError("Repository name given is invalid") - self._container_version = container_data[1] + self._repository_version = repository_data[1] - if "://" in container_data[0]: - scheme = container_data[0].split(":", 1)[0].lower() + if "://" in repository_data[0]: + scheme = repository_data[0].split(":", 1)[0].lower() insecure = scheme != "https" - self._container_url = container_data[0] + self._repository_url = repository_data[0] else: scheme = "http" if insecure else "https" - self._container_url = f"{scheme}://{container_data[0]}" + self._repository_url = f"{scheme}://{repository_data[0]}" - container_url_data = urlsplit(self._container_url) + repository_url_data = urlsplit(self._repository_url) self._token = None if token is None: @@ -93,7 +93,7 @@ def __init__( Registry.__init__( self, - hostname=container_url_data.netloc, + hostname=repository_url_data.netloc, auth_backend=auth_backend, insecure=insecure, ) @@ -101,7 +101,7 @@ def __init__( if logger is None or not logger.hasHandlers(): logger = LoggerSetup.get_logger("gardenlinux.oci") - self._container_name = container_url_data.path[1:] + self._repository_name = repository_url_data.path[1:] self._logger = logger if self._token is not None: @@ -113,7 +113,9 @@ def __init__( # Login to registry if credentials are provided if username and password: - self._logger.debug("Logging in with username/password") + self._logger.debug( + "gardenlinux.oci.Repository logging in with username/password" + ) try: self.login(username, password) @@ -123,9 +125,9 @@ def __init__( def generate_image_manifest( self, cname: str, - architecture: Optional[str] = None, - version: Optional[str] = None, - commit: Optional[str] = None, + architecture: Optional[str], + version: Optional[str], + commit: Optional[str], feature_set: Optional[str] = None, ) -> ImageManifest: """ @@ -141,31 +143,21 @@ def generate_image_manifest( :since: 0.10.0 """ - cname_object = CName(cname, architecture, version) - - if architecture is None: - architecture = cname_object.arch - if version is None: - version = cname_object.version - if commit is None: - commit = cname_object.commit_id - if feature_set is None: - feature_set = cname_object.feature_set - - if commit is None: - commit = "" + if not architecture or not version or not commit: + raise ValueError( + "Failed to validate input for generating an OCI image manifest" + ) + abn_object = ArtifactBaseName(f"{cname}-{architecture}-{version}-{commit}") manifest = ImageManifest() - manifest.version = version # type: ignore[assignment] - manifest.cname = cname - manifest.arch = architecture # type: ignore[assignment] - manifest.feature_set = feature_set + manifest.flavor = abn_object.flavor + manifest.version = version manifest.commit = commit description = ( - f"Image: {cname} " - f"Flavor: {cname_object.flavor} " + f"Image: {cname}-{architecture}-{version}-{commit}" + f"Flavor: {cname}-{architecture} " f"Architecture: {architecture} " f"Features: {feature_set} " f"Commit: {commit} " @@ -198,11 +190,8 @@ def generate_manifest( """ Generates an OCI manifest - :param cname: Canonical name of the manifest - :param architecture: Target architecture of the manifest :param version: Artifacts version of the manifest :param commit: The commit hash of the manifest - :param feature_set: The expanded list of the included features of this manifest :return: (object) OCI manifest :since: 0.9.2 @@ -226,7 +215,7 @@ def _get_index_without_response_parsing(self) -> Response: """ manifest_url = self.get_container( - f"{self._container_name}:{self._container_version}" + f"{self._repository_name}:{self._repository_version}" ).manifest_url() return self.do_request( # type: ignore[no-any-return] @@ -243,7 +232,7 @@ def _get_manifest_without_response_parsing(self, reference: str) -> Response: """ return self.do_request( # type: ignore[no-any-return] - f"{self.prefix}://{self.hostname}/v2/{self._container_name}/manifests/{reference}", + f"{self.prefix}://{self.hostname}/v2/{self._repository_name}/manifests/{reference}", headers={"Accept": "application/vnd.oci.image.manifest.v1+json"}, ) @@ -300,7 +289,7 @@ def push_index_from_directory( if manifest["digest"] == existing_manifest["digest"]: self._logger.debug( - f"Skipping manifest with digest {manifest['digest']} - already exists" + f"gardenlinux.oci.Repository.push_index_from_directory(): Skipping manifest with digest {manifest['digest']} - already exists" ) continue @@ -359,7 +348,7 @@ def push_manifest( if not isinstance(manifest, Manifest): raise RuntimeError("Artifacts image manifest given is invalid") - container_name = f"{self._container_name}:{self._container_version}" + repository_name = f"{self._repository_name}:{self._repository_version}" fd, config_file = mkstemp() @@ -368,24 +357,28 @@ def push_manifest( fp.write(manifest.config_json) self._check_200_response( - self.upload_blob(config_file, container_name, manifest["config"]) + self.upload_blob(config_file, repository_name, manifest["config"]) ) - self._logger.debug(f"Successfully pushed config for {container_name}") + self._logger.debug( + f"gardenlinux.oci.Repository.push_manifest(): Successfully pushed config for {repository_name}" + ) finally: Path(config_file).unlink() - manifest_url = f"{self._container_url}:{self._container_version}" + manifest_url = f"{self._repository_url}:{self._repository_version}" if isinstance(manifest, ImageManifest): - manifest_url += f"-{manifest.cname}-{manifest.arch}" + manifest_url += f"-{manifest.flavor}-{manifest.version}-{manifest.commit}-{manifest.arch}" + elif not self._repository_version: + raise RuntimeError("Failed to push OCI manifest with invalid tag") - manifest_container = OrasContainer(manifest_url) + manifest_repository = OrasContainer(manifest_url) - self._check_200_response(self.upload_manifest(manifest, manifest_container)) + self._check_200_response(self.upload_manifest(manifest, manifest_repository)) self._logger.info( - f"Successfully pushed {manifest_container} ({manifest.digest})" + f"Successfully pushed {manifest_repository} ({manifest.digest})" ) if isinstance(additional_tags, Sequence) and len(additional_tags) > 0: @@ -429,7 +422,7 @@ def push_manifest_and_artifacts( if not isinstance(artifacts_dir, PathLike): artifacts_dir = Path(artifacts_dir) - container_name = f"{self._container_name}:{self._container_version}" + repository_name = f"{self._repository_name}:{self._repository_version}" # For each file, create sign, attach and push a layer for artifact in artifacts_with_metadata: @@ -453,10 +446,12 @@ def push_manifest_and_artifacts( manifest.append_layer(layer) layer_dict = layer.dict - self._logger.debug(f"Layer: {layer_dict}") + self._logger.debug( + f"gardenlinux.oci.Repository.push_manifest_and_artifacts(): {layer_dict}" + ) self._check_200_response( - self.upload_blob(file_path_name, container_name, layer_dict) + self.upload_blob(file_path_name, repository_name, layer_dict) ) self._logger.info( @@ -506,7 +501,7 @@ def push_manifest_and_artifacts_from_directory( if file_name.is_file() ] - artifacts_with_metadata = Container.get_artifacts_metadata_from_files( + artifacts_with_metadata = Repository.get_artifacts_metadata_from_files( files, manifest.arch ) @@ -547,9 +542,11 @@ def push_manifest_for_tags(self, manifest: Manifest, tags: List[str]) -> None: # For each additional tag, push the manifest using Registry.upload_manifest for tag in tags: - manifest_container = OrasContainer(f"{self._container_url}:{tag}") + manifest_repository = OrasContainer(f"{self._repository_url}:{tag}") - self._check_200_response(self.upload_manifest(manifest, manifest_container)) + self._check_200_response( + self.upload_manifest(manifest, manifest_repository) + ) def read_index(self) -> Index: """ @@ -573,6 +570,7 @@ def read_manifest( cname: Optional[str] = None, architecture: Optional[str] = None, version: Optional[str] = None, + commit: Optional[str] = None, ) -> Manifest: """ Reads the OCI manifest from registry. @@ -580,6 +578,7 @@ def read_manifest( :param cname: Canonical name of the manifest :param architecture: Target architecture of the manifest :param version: Artifacts version of the manifest + :param commit: The Git commit ID of the manifest :return: OCI image manifest :since: 1.0.0 @@ -589,16 +588,14 @@ def read_manifest( manifest_type = Manifest response = self._get_manifest_without_response_parsing( - self._container_version + self._repository_version ) else: + abn_object = ArtifactBaseName(f"{cname}-{architecture}-{version}-{commit}") manifest_type = ImageManifest - if architecture is None: - architecture = CName(cname, architecture, version).arch - response = self._get_manifest_without_response_parsing( - f"{self._container_version}-{cname}-{architecture}" + f"{self._repository_version}-{abn_object}-{architecture}" ) if response.ok: @@ -619,7 +616,11 @@ def read_or_generate_index(self) -> Index: try: index = self.read_index() except HTTPError as exc: - if exc.response.status_code != 404: + if exc.response.status_code == 404: + self._logger.debug( + f"gardenlinux.oci.Repository.read_index() failed: {exc}" + ) + else: raise index = self.generate_index() @@ -647,18 +648,24 @@ def read_or_generate_manifest( :since: 0.7.0 """ - try: - manifest = self.read_manifest(cname, architecture, version) - except HTTPError as exc: - if exc.response.status_code != 404: - raise + manifest = None - if cname is None: - manifest = self.generate_manifest(version, commit) - else: - manifest = self.generate_image_manifest( - cname, architecture, version, commit, feature_set - ) + if cname: + try: + manifest = self.read_manifest(cname, architecture, version, commit) + except HTTPError as exc: + if exc.response.status_code == 404: + self._logger.debug( + f"gardenlinux.oci.Repository.read_manifest() failed: {exc}" + ) + else: + raise + + manifest = self.generate_image_manifest( + cname, architecture, version, commit, feature_set + ) + else: + manifest = self.generate_manifest(version, commit) return manifest @@ -667,7 +674,7 @@ def _upload_index(self, index: Index, reference: Optional[str] = None) -> Respon Uploads the given OCI image index and returns the response. :param index: OCI image index - :param reference: OCI container reference (tag) to push to + :param reference: OCI repository reference (tag) to push to :return: (object) OCI image index put response :since: 0.7.0 @@ -676,27 +683,29 @@ def _upload_index(self, index: Index, reference: Optional[str] = None) -> Respon jsonschema.validate(index, schema=IndexSchema) if reference is None: - reference = self._container_version + reference = self._repository_version return self.do_request( # type: ignore[no-any-return] - f"{self.prefix}://{self.hostname}/v2/{self._container_name}/manifests/{reference}", + f"{self.prefix}://{self.hostname}/v2/{self._repository_name}/manifests/{reference}", "PUT", headers={"Content-Type": OCI_IMAGE_INDEX_MEDIA_TYPE}, json=index.extended_dict, ) - def upload_manifest(self, manifest: Manifest, container: OrasContainer) -> Response: + def upload_manifest( + self, manifest: Manifest, repository: OrasContainer + ) -> Response: """ oras-project.github.io: Read a manifest file and upload it. - :param manifest: manifest to upload - :param container: parsed container URI + :param manifest: Manifest to upload + :param repository: Repository URI :return: (object) OCI manifest put response :since: 1.0.0 """ - return Registry.upload_manifest(self, manifest.extended_dict, container) # type: ignore[no-any-return] + return Registry.upload_manifest(self, manifest.extended_dict, repository) # type: ignore[no-any-return] @staticmethod def get_artifacts_metadata_from_files( diff --git a/src/gardenlinux/s3/__main__.py b/src/gardenlinux/s3/__main__.py index f794631c..b0cb7505 100644 --- a/src/gardenlinux/s3/__main__.py +++ b/src/gardenlinux/s3/__main__.py @@ -7,6 +7,7 @@ import argparse +from ..logger import LoggerSetup from .s3_artifacts import S3Artifacts @@ -43,16 +44,23 @@ def get_parser() -> argparse.ArgumentParser: download_parser = subparsers.add_parser("download-artifacts-from-bucket") download_parser.add_argument( - "--cname", + "--artifact-base-name", required=False, - dest="cname", - help="Canonical name (cname) used as the S3 key prefix for artifacts.", + dest="artifact_base_name", + help="Artifact base name used as the S3 key prefix for artifacts.", + ) + + download_parser.add_argument( + "--ignore-missing", + dest="ignore_missing", + action="store_true", + help="Create a log entry only if the given S3 key prefix has not been found.", ) upload_parser = subparsers.add_parser("upload-artifacts-to-bucket") upload_parser.add_argument( - "--artifact-name", dest="artifact_name", help="S3 artifact base name." + "--artifact-base-name", dest="artifact_base_name", help="S3 artifact base name." ) return parser @@ -69,8 +77,18 @@ def main() -> None: args = parser.parse_args() if args.action == "download-artifacts-from-bucket": - S3Artifacts(args.bucket).download_to_directory(args.cname, args.path) + try: + S3Artifacts(args.bucket).download_to_directory( + args.artifact_base_name, args.path + ) + except RuntimeError as exc: + if not args.ignore_missing: + raise + + LoggerSetup.get_logger("gardenlinux.s3").warning( + f"gl-s3 download-artifacts-from-bucket failed: {exc}" + ) elif args.action == "upload-artifacts-to-bucket": S3Artifacts(args.bucket).upload_from_directory( - args.artifact_name, args.path, dry_run=args.dry_run + args.artifact_base_name, args.path, dry_run=args.dry_run ) diff --git a/src/gardenlinux/s3/bucket.py b/src/gardenlinux/s3/bucket.py index 37d0e3b4..96ab4f37 100644 --- a/src/gardenlinux/s3/bucket.py +++ b/src/gardenlinux/s3/bucket.py @@ -74,7 +74,7 @@ def objects(self) -> "BucketObjectsCollection": :since: 0.8.0 """ - self._logger.debug(f"Returning all S3 bucket objects for {self._bucket.name}") + self._logger.debug(f"gardenlinux.s3.Bucket.objects(): {self._bucket.name}") return self._bucket.objects.all() diff --git a/src/gardenlinux/s3/s3_artifacts.py b/src/gardenlinux/s3/s3_artifacts.py index 09fd6a37..6dd082d5 100644 --- a/src/gardenlinux/s3/s3_artifacts.py +++ b/src/gardenlinux/s3/s3_artifacts.py @@ -18,7 +18,7 @@ import yaml -from ..features import CName +from ..features import ArtifactBaseName from .bucket import Bucket @@ -67,13 +67,13 @@ def bucket(self) -> Bucket: return self._bucket def download_to_directory( - self, cname: str, artifacts_dir: PathLike[str] | str + self, artifact_base_name: str, artifacts_dir: PathLike[str] | str ) -> None: """ Download S3 artifacts to a given directory. - :param cname: Canonical name of the GardenLinux S3 artifacts - :param artifacts_dir: Path for the image artifacts + :param artifact_base_name: Artifact base name of the Garden Linux S3 artifacts + :param artifacts_dir: Path for the image artifacts :since: 0.8.0 """ @@ -83,15 +83,25 @@ def download_to_directory( if not artifacts_dir.is_dir(): raise RuntimeError(f"Artifacts directory given is invalid: {artifacts_dir}") - release_object = list( - self._bucket.objects.filter(Prefix=f"meta/singles/{cname}") - )[0] + try: + release_object = next( + iter( + self._bucket.objects.filter( + Prefix=f"meta/singles/{artifact_base_name}" + ) + ) + ) + except StopIteration: + raise RuntimeError(f"S3 artifact given is invalid: {artifact_base_name}") self._bucket.download_file( - release_object.key, str(artifacts_dir.joinpath(f"{cname}.s3_metadata.yaml")) + release_object.key, + str(artifacts_dir.joinpath(f"{artifact_base_name}.s3_metadata.yaml")), ) - for s3_object in self._bucket.objects.filter(Prefix=f"objects/{cname}").all(): + for s3_object in self._bucket.objects.filter( + Prefix=f"objects/{artifact_base_name}" + ).all(): self._bucket.download_file( s3_object.key, str(artifacts_dir.joinpath(basename(s3_object.key))) ) @@ -121,35 +131,44 @@ def upload_from_directory( release_file = artifacts_dir.joinpath(f"{base_name}.release") try: - cname_object = CName.new_from_release_file(release_file) + abn_object = ArtifactBaseName.new_from_release_file(release_file) except RuntimeError: if not release_file.exists(): raise RuntimeError( f"Release metadata file given is invalid: {release_file}" ) + base_abn_object = ArtifactBaseName(base_name) + release_config = ConfigParser(allow_unnamed_section=True) release_config.read(release_file) - cname_object = CName( - release_config.get(UNNAMED_SECTION, "GARDENLINUX_CNAME").strip("\"'"), - commit_hash=release_config.get( - UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG" - ).strip("\"'"), - version=release_config.get( - UNNAMED_SECTION, "GARDENLINUX_VERSION" - ).strip("\"'"), - ) + artifact_base_name = release_config.get( + UNNAMED_SECTION, "GARDENLINUX_CNAME" + ).strip("\"'") - if cname_object.version_and_commit_id is None: + artifact_base_name += "-" + base_abn_object.arch + + artifact_base_name += "-" + release_config.get( + UNNAMED_SECTION, "GARDENLINUX_VERSION" + ).strip("\"'") + + artifact_base_name += "-" + release_config.get( + UNNAMED_SECTION, "GARDENLINUX_COMMIT_ID_LONG" + ).strip("\"'") + + abn_object = ArtifactBaseName(artifact_base_name) + + if abn_object.version_and_commit_id is None: raise RuntimeError( "Version information could not be determined from release file" ) - arch = cname_object.arch - feature_set_list = cname_object.feature_set_list + arch = abn_object.arch + feature_set_list = abn_object.feature_set_list release_timestamp = stat(release_file).st_ctime requirements_file = artifacts_dir.joinpath(f"{base_name}.requirements") + publishing_group = "" require_uefi = None secureboot = None @@ -196,13 +215,13 @@ def upload_from_directory( re_object = re.compile("[^a-zA-Z0-9\\s+\\-=.\\_:/@]") arch = re_object.sub("+", arch) - commit_id_or_hash = cname_object.commit_hash + commit_id_or_hash = abn_object.commit_hash if commit_id_or_hash is None: - commit_id_or_hash = cname_object.commit_id + commit_id_or_hash = abn_object.commit_id metadata = { - "platform": cname_object.platform, + "platform": abn_object.platform, "architecture": arch, "build_committish": commit_id_or_hash, "build_timestamp": datetime.fromtimestamp(release_timestamp), @@ -214,14 +233,14 @@ def upload_from_directory( "s3_bucket": self._bucket.name, "s3_key": f"meta/singles/{base_name}", "test_result": None, - "version": cname_object.version, + "version": abn_object.version, "paths": [], } - if cname_object.version_epoch is not None: - metadata["gardenlinux_epoch"] = cname_object.version_epoch + if abn_object.version_epoch is not None: + metadata["gardenlinux_epoch"] = abn_object.version_epoch - platform_variant = cname_object.platform_variant + platform_variant = abn_object.platform_variant if platform_variant is not None: metadata["platform_variant"] = platform_variant @@ -253,8 +272,8 @@ def upload_from_directory( s3_tags = { "architecture": arch, - "platform": re_object.sub("+", cname_object.platform), - "version": re_object.sub("+", cname_object.version), # type: ignore[arg-type] + "platform": re_object.sub("+", abn_object.platform), + "version": re_object.sub("+", abn_object.version), "committish": commit_id_or_hash, "md5sum": md5sum, "sha256sum": sha256sum, diff --git a/test-data/gardenlinux b/test-data/gardenlinux index 8c14e750..c15e9789 160000 --- a/test-data/gardenlinux +++ b/test-data/gardenlinux @@ -1 +1 @@ -Subproject commit 8c14e75011397cd6d16c1182f3377678c885b87a +Subproject commit c15e9789b16b0e64019b52b45fb6fa3b3c0f608c diff --git a/test-data/reproducibility/diff_files/compare_nightly.md b/test-data/reproducibility/diff_files/compare_nightly.md index 1f41fd03..a5843bda 100644 --- a/test-data/reproducibility/diff_files/compare_nightly.md +++ b/test-data/reproducibility/diff_files/compare_nightly.md @@ -13,7 +13,7 @@ Comparison of nightly **[#2405](https://github.com/gardenlinux/gardenlinux/actio | Affected Files | Flavors | Features Causing the Problem | |----------------|---------|------------------------------| -|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container
| +|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container:
_archgrouped
| |✅ No problems found|**95.1%**
ali-gardener_prod-amd64...`ali-gardener_prod-amd64`
`aws-gardener_fips_prod-amd64`
`aws-gardener_fips_prod-arm64`
`aws-gardener_prod-amd64`
`aws-gardener_prod-arm64`
`aws-gardener_prod_tpm2_trustedboot-amd64`
`aws-gardener_prod_tpm2_trustedboot-arm64`
`aws-gardener_prod_trustedboot-amd64`
`aws-gardener_prod_trustedboot-arm64`
`aws-gardener_prod_usi-amd64`
`aws-gardener_prod_usi-arm64`
`azure-gardener_prod-amd64`
`azure-gardener_prod-arm64`
`azure-gardener_prod_tpm2_trustedboot-amd64`
`azure-gardener_prod_tpm2_trustedboot-arm64`
`azure-gardener_prod_trustedboot-amd64`
`azure-gardener_prod_trustedboot-arm64`
`azure-gardener_prod_usi-amd64`
`azure-gardener_prod_usi-arm64`
`bare-libc-amd64`
`bare-libc-arm64`
`bare-nodejs-amd64`
`bare-nodejs-arm64`
`bare-python-amd64`
`bare-python-arm64`
`bare-sapmachine-amd64`
`bare-sapmachine-arm64`
`baremetal-capi-amd64`
`baremetal-capi-arm64`
`baremetal-gardener_prod-amd64`
`baremetal-gardener_prod-arm64`
`baremetal-gardener_prod_tpm2_trustedboot-amd64`
`baremetal-gardener_prod_tpm2_trustedboot-arm64`
`baremetal-gardener_prod_trustedboot-amd64`
`baremetal-gardener_prod_trustedboot-arm64`
`baremetal-gardener_prod_usi-amd64`
`baremetal-gardener_prod_usi-arm64`
`baremetal-gardener_pxe-amd64`
`baremetal-gardener_pxe-arm64`
`baremetal-vhost-amd64`
`baremetal-vhost-arm64`
`baremetal_pxe-amd64`
`baremetal_pxe-arm64`
`gcp-gardener_prod-amd64`
`gcp-gardener_prod-arm64`
`gcp-gardener_prod_tpm2_trustedboot-amd64`
`gcp-gardener_prod_tpm2_trustedboot-arm64`
`gcp-gardener_prod_trustedboot-amd64`
`gcp-gardener_prod_trustedboot-arm64`
`gcp-gardener_prod_usi-amd64`
`gcp-gardener_prod_usi-arm64`
`gdch-gardener_prod-amd64`
`gdch-gardener_prod-arm64`
`kvm-gardener_prod-amd64`
`kvm-gardener_prod-arm64`
`kvm-gardener_prod_tpm2_trustedboot-amd64`
`kvm-gardener_prod_tpm2_trustedboot-arm64`
`kvm-gardener_prod_trustedboot-amd64`
`kvm-gardener_prod_trustedboot-arm64`
`kvm-gardener_prod_usi-amd64`
`kvm-gardener_prod_usi-arm64`
`lima-amd64`
`lima-arm64`
`openstack-gardener_prod-amd64`
`openstack-gardener_prod-arm64`
`openstack-gardener_prod_tpm2_trustedboot-amd64`
`openstack-gardener_prod_tpm2_trustedboot-arm64`
`openstack-gardener_prod_trustedboot-amd64`
`openstack-gardener_prod_trustedboot-arm64`
`openstack-gardener_prod_usi-amd64`
`openstack-gardener_prod_usi-arm64`
`openstack-metal-gardener_prod-amd64`
`openstack-metal-gardener_prod-arm64`
`openstack-metal-gardener_prod_usi-amd64`
`openstack-metal-gardener_prod_usi-arm64`
`vmware-gardener_prod-amd64`
`vmware-gardener_prod-arm64`
|-| *To add affected files to the whitelist, edit `src/gardenlinux/features/reproducibility/nightly_whitelist.json` in python-gardenlinux-lib* diff --git a/test-data/reproducibility/diff_files/compare_nightly_different_commit.md b/test-data/reproducibility/diff_files/compare_nightly_different_commit.md index e6d3a430..16b2a7ba 100644 --- a/test-data/reproducibility/diff_files/compare_nightly_different_commit.md +++ b/test-data/reproducibility/diff_files/compare_nightly_different_commit.md @@ -15,7 +15,7 @@ Comparison of nightly **[#2405](https://github.com/gardenlinux/gardenlinux/actio | Affected Files | Flavors | Features Causing the Problem | |----------------|---------|------------------------------| -|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container
| +|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container:
_archgrouped
| |✅ No problems found|**95.1%**
ali-gardener_prod-amd64...`ali-gardener_prod-amd64`
`aws-gardener_fips_prod-amd64`
`aws-gardener_fips_prod-arm64`
`aws-gardener_prod-amd64`
`aws-gardener_prod-arm64`
`aws-gardener_prod_tpm2_trustedboot-amd64`
`aws-gardener_prod_tpm2_trustedboot-arm64`
`aws-gardener_prod_trustedboot-amd64`
`aws-gardener_prod_trustedboot-arm64`
`aws-gardener_prod_usi-amd64`
`aws-gardener_prod_usi-arm64`
`azure-gardener_prod-amd64`
`azure-gardener_prod-arm64`
`azure-gardener_prod_tpm2_trustedboot-amd64`
`azure-gardener_prod_tpm2_trustedboot-arm64`
`azure-gardener_prod_trustedboot-amd64`
`azure-gardener_prod_trustedboot-arm64`
`azure-gardener_prod_usi-amd64`
`azure-gardener_prod_usi-arm64`
`bare-libc-amd64`
`bare-libc-arm64`
`bare-nodejs-amd64`
`bare-nodejs-arm64`
`bare-python-amd64`
`bare-python-arm64`
`bare-sapmachine-amd64`
`bare-sapmachine-arm64`
`baremetal-capi-amd64`
`baremetal-capi-arm64`
`baremetal-gardener_prod-amd64`
`baremetal-gardener_prod-arm64`
`baremetal-gardener_prod_tpm2_trustedboot-amd64`
`baremetal-gardener_prod_tpm2_trustedboot-arm64`
`baremetal-gardener_prod_trustedboot-amd64`
`baremetal-gardener_prod_trustedboot-arm64`
`baremetal-gardener_prod_usi-amd64`
`baremetal-gardener_prod_usi-arm64`
`baremetal-gardener_pxe-amd64`
`baremetal-gardener_pxe-arm64`
`baremetal-vhost-amd64`
`baremetal-vhost-arm64`
`baremetal_pxe-amd64`
`baremetal_pxe-arm64`
`gcp-gardener_prod-amd64`
`gcp-gardener_prod-arm64`
`gcp-gardener_prod_tpm2_trustedboot-amd64`
`gcp-gardener_prod_tpm2_trustedboot-arm64`
`gcp-gardener_prod_trustedboot-amd64`
`gcp-gardener_prod_trustedboot-arm64`
`gcp-gardener_prod_usi-amd64`
`gcp-gardener_prod_usi-arm64`
`gdch-gardener_prod-amd64`
`gdch-gardener_prod-arm64`
`kvm-gardener_prod-amd64`
`kvm-gardener_prod-arm64`
`kvm-gardener_prod_tpm2_trustedboot-amd64`
`kvm-gardener_prod_tpm2_trustedboot-arm64`
`kvm-gardener_prod_trustedboot-amd64`
`kvm-gardener_prod_trustedboot-arm64`
`kvm-gardener_prod_usi-amd64`
`kvm-gardener_prod_usi-arm64`
`lima-amd64`
`lima-arm64`
`openstack-gardener_prod-amd64`
`openstack-gardener_prod-arm64`
`openstack-gardener_prod_tpm2_trustedboot-amd64`
`openstack-gardener_prod_tpm2_trustedboot-arm64`
`openstack-gardener_prod_trustedboot-amd64`
`openstack-gardener_prod_trustedboot-arm64`
`openstack-gardener_prod_usi-amd64`
`openstack-gardener_prod_usi-arm64`
`openstack-metal-gardener_prod-amd64`
`openstack-metal-gardener_prod-arm64`
`openstack-metal-gardener_prod_usi-amd64`
`openstack-metal-gardener_prod_usi-arm64`
`vmware-gardener_prod-amd64`
`vmware-gardener_prod-arm64`
|-| *To add affected files to the whitelist, edit `src/gardenlinux/features/reproducibility/nightly_whitelist.json` in python-gardenlinux-lib* diff --git a/test-data/reproducibility/diff_files/different_commit.md b/test-data/reproducibility/diff_files/different_commit.md index c23088c5..49a532ae 100644 --- a/test-data/reproducibility/diff_files/different_commit.md +++ b/test-data/reproducibility/diff_files/different_commit.md @@ -13,7 +13,7 @@ Comparison of the latest nightly **[#2365](https://github.com/gardenlinux/garden | Affected Files | Flavors | Features Causing the Problem | |----------------|---------|------------------------------| -|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container
| +|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container:
_archgrouped
| |✅ No problems found|**95.1%**
ali-gardener_prod-amd64...`ali-gardener_prod-amd64`
`aws-gardener_fips_prod-amd64`
`aws-gardener_fips_prod-arm64`
`aws-gardener_prod-amd64`
`aws-gardener_prod-arm64`
`aws-gardener_prod_tpm2_trustedboot-amd64`
`aws-gardener_prod_tpm2_trustedboot-arm64`
`aws-gardener_prod_trustedboot-amd64`
`aws-gardener_prod_trustedboot-arm64`
`aws-gardener_prod_usi-amd64`
`aws-gardener_prod_usi-arm64`
`azure-gardener_prod-amd64`
`azure-gardener_prod-arm64`
`azure-gardener_prod_tpm2_trustedboot-amd64`
`azure-gardener_prod_tpm2_trustedboot-arm64`
`azure-gardener_prod_trustedboot-amd64`
`azure-gardener_prod_trustedboot-arm64`
`azure-gardener_prod_usi-amd64`
`azure-gardener_prod_usi-arm64`
`bare-libc-amd64`
`bare-libc-arm64`
`bare-nodejs-amd64`
`bare-nodejs-arm64`
`bare-python-amd64`
`bare-python-arm64`
`bare-sapmachine-amd64`
`bare-sapmachine-arm64`
`baremetal-capi-amd64`
`baremetal-capi-arm64`
`baremetal-gardener_prod-amd64`
`baremetal-gardener_prod-arm64`
`baremetal-gardener_prod_tpm2_trustedboot-amd64`
`baremetal-gardener_prod_tpm2_trustedboot-arm64`
`baremetal-gardener_prod_trustedboot-amd64`
`baremetal-gardener_prod_trustedboot-arm64`
`baremetal-gardener_prod_usi-amd64`
`baremetal-gardener_prod_usi-arm64`
`baremetal-gardener_pxe-amd64`
`baremetal-gardener_pxe-arm64`
`baremetal-vhost-amd64`
`baremetal-vhost-arm64`
`baremetal_pxe-amd64`
`baremetal_pxe-arm64`
`gcp-gardener_prod-amd64`
`gcp-gardener_prod-arm64`
`gcp-gardener_prod_tpm2_trustedboot-amd64`
`gcp-gardener_prod_tpm2_trustedboot-arm64`
`gcp-gardener_prod_trustedboot-amd64`
`gcp-gardener_prod_trustedboot-arm64`
`gcp-gardener_prod_usi-amd64`
`gcp-gardener_prod_usi-arm64`
`gdch-gardener_prod-amd64`
`gdch-gardener_prod-arm64`
`kvm-gardener_prod-amd64`
`kvm-gardener_prod-arm64`
`kvm-gardener_prod_tpm2_trustedboot-amd64`
`kvm-gardener_prod_tpm2_trustedboot-arm64`
`kvm-gardener_prod_trustedboot-amd64`
`kvm-gardener_prod_trustedboot-arm64`
`kvm-gardener_prod_usi-amd64`
`kvm-gardener_prod_usi-arm64`
`lima-amd64`
`lima-arm64`
`openstack-gardener_prod-amd64`
`openstack-gardener_prod-arm64`
`openstack-gardener_prod_tpm2_trustedboot-amd64`
`openstack-gardener_prod_tpm2_trustedboot-arm64`
`openstack-gardener_prod_trustedboot-amd64`
`openstack-gardener_prod_trustedboot-arm64`
`openstack-gardener_prod_usi-amd64`
`openstack-gardener_prod_usi-arm64`
`openstack-metal-gardener_prod-amd64`
`openstack-metal-gardener_prod-arm64`
`openstack-metal-gardener_prod_usi-amd64`
`openstack-metal-gardener_prod_usi-arm64`
`vmware-gardener_prod-amd64`
`vmware-gardener_prod-arm64`
|-| *To add affected files to the whitelist, edit `src/gardenlinux/features/reproducibility/nightly_whitelist.json` in python-gardenlinux-lib* diff --git a/test-data/reproducibility/diff_files/one_issue.md b/test-data/reproducibility/diff_files/one_issue.md index 5c09d2ba..d5ae281d 100644 --- a/test-data/reproducibility/diff_files/one_issue.md +++ b/test-data/reproducibility/diff_files/one_issue.md @@ -9,7 +9,7 @@ | Affected Files | Flavors | Features Causing the Problem | |----------------|---------|------------------------------| -|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container
| +|`/etc/hostname`|**4.9%** affected
`container-amd64`
`container-arm64`
`container-pythonDev-amd64`
`container-pythonDev-arm64`|
container:
_archgrouped
| |✅ No problems found|**95.1%**
ali-gardener_prod-amd64...`ali-gardener_prod-amd64`
`aws-gardener_fips_prod-amd64`
`aws-gardener_fips_prod-arm64`
`aws-gardener_prod-amd64`
`aws-gardener_prod-arm64`
`aws-gardener_prod_tpm2_trustedboot-amd64`
`aws-gardener_prod_tpm2_trustedboot-arm64`
`aws-gardener_prod_trustedboot-amd64`
`aws-gardener_prod_trustedboot-arm64`
`aws-gardener_prod_usi-amd64`
`aws-gardener_prod_usi-arm64`
`azure-gardener_prod-amd64`
`azure-gardener_prod-arm64`
`azure-gardener_prod_tpm2_trustedboot-amd64`
`azure-gardener_prod_tpm2_trustedboot-arm64`
`azure-gardener_prod_trustedboot-amd64`
`azure-gardener_prod_trustedboot-arm64`
`azure-gardener_prod_usi-amd64`
`azure-gardener_prod_usi-arm64`
`bare-libc-amd64`
`bare-libc-arm64`
`bare-nodejs-amd64`
`bare-nodejs-arm64`
`bare-python-amd64`
`bare-python-arm64`
`bare-sapmachine-amd64`
`bare-sapmachine-arm64`
`baremetal-capi-amd64`
`baremetal-capi-arm64`
`baremetal-gardener_prod-amd64`
`baremetal-gardener_prod-arm64`
`baremetal-gardener_prod_tpm2_trustedboot-amd64`
`baremetal-gardener_prod_tpm2_trustedboot-arm64`
`baremetal-gardener_prod_trustedboot-amd64`
`baremetal-gardener_prod_trustedboot-arm64`
`baremetal-gardener_prod_usi-amd64`
`baremetal-gardener_prod_usi-arm64`
`baremetal-gardener_pxe-amd64`
`baremetal-gardener_pxe-arm64`
`baremetal-vhost-amd64`
`baremetal-vhost-arm64`
`baremetal_pxe-amd64`
`baremetal_pxe-arm64`
`gcp-gardener_prod-amd64`
`gcp-gardener_prod-arm64`
`gcp-gardener_prod_tpm2_trustedboot-amd64`
`gcp-gardener_prod_tpm2_trustedboot-arm64`
`gcp-gardener_prod_trustedboot-amd64`
`gcp-gardener_prod_trustedboot-arm64`
`gcp-gardener_prod_usi-amd64`
`gcp-gardener_prod_usi-arm64`
`gdch-gardener_prod-amd64`
`gdch-gardener_prod-arm64`
`kvm-gardener_prod-amd64`
`kvm-gardener_prod-arm64`
`kvm-gardener_prod_tpm2_trustedboot-amd64`
`kvm-gardener_prod_tpm2_trustedboot-arm64`
`kvm-gardener_prod_trustedboot-amd64`
`kvm-gardener_prod_trustedboot-arm64`
`kvm-gardener_prod_usi-amd64`
`kvm-gardener_prod_usi-arm64`
`lima-amd64`
`lima-arm64`
`openstack-gardener_prod-amd64`
`openstack-gardener_prod-arm64`
`openstack-gardener_prod_tpm2_trustedboot-amd64`
`openstack-gardener_prod_tpm2_trustedboot-arm64`
`openstack-gardener_prod_trustedboot-amd64`
`openstack-gardener_prod_trustedboot-arm64`
`openstack-gardener_prod_usi-amd64`
`openstack-gardener_prod_usi-arm64`
`openstack-metal-gardener_prod-amd64`
`openstack-metal-gardener_prod-arm64`
`openstack-metal-gardener_prod_usi-amd64`
`openstack-metal-gardener_prod_usi-arm64`
`vmware-gardener_prod-amd64`
`vmware-gardener_prod-arm64`
|-| *To add affected files to the whitelist, edit `src/gardenlinux/features/reproducibility/nightly_whitelist.json` in python-gardenlinux-lib* diff --git a/tests/conftest.py b/tests/conftest.py index 093ad3dc..fcb3e4be 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -138,11 +138,16 @@ def zot_session() -> Generator[subprocess.Popen[Any]]: os.close(fd) zot_config = { - "distSpecVersion": "1.1.0", - "storage": {"rootDirectory": "output/registry/zot"}, + "distSpecVersion": "1.1.1", + "storage": { + "rootDirectory": "output/registry/zot", + "commit": True, + "gc": False, + }, "http": { "address": "127.0.0.1", "port": "18081", + "externalURL": "http://127.0.0.1:18081", "auth": {"htpasswd": {"path": f"{htpasswd_file}"}}, "accessControl": { "repositories": { diff --git a/tests/constants.py b/tests/constants.py index 6a2bd967..28a260b2 100644 --- a/tests/constants.py +++ b/tests/constants.py @@ -11,7 +11,7 @@ REGISTRY = "127.0.0.1:18081" REGISTRY_URL = f"http://{REGISTRY}" REPO_NAME = "gardenlinux-example" -CONTAINER_NAME_ZOT_EXAMPLE = f"{REGISTRY}/{REPO_NAME}" +REPOSITORY_NAME_ZOT_EXAMPLE = f"{REGISTRY}/{REPO_NAME}" GARDENLINUX_ROOT_DIR_EXAMPLE = f"{TEST_DATA_DIR}/gardenlinux/.build" TEST_PLATFORMS = ["aws", "azure", "baremetal", "gcp", "openstack"] diff --git a/tests/features/constants.py b/tests/features/constants.py index e99ac286..d92df8e9 100644 --- a/tests/features/constants.py +++ b/tests/features/constants.py @@ -7,25 +7,29 @@ ) -def generate_container_amd64_release_metadata(version: str, commit_hash: str) -> str: - return f""" +def generate_container_release_metadata( + version: str, commit_hash: str, arch: str = "amd64", variant: str = "" +) -> str: + metadata = f""" ID={GL_RELEASE_ID} ID_LIKE=debian NAME="{GL_DISTRIBUTION_NAME}" PRETTY_NAME="{GL_DISTRIBUTION_NAME} {version}" IMAGE_VERSION={version} -VARIANT_ID="container-amd64" +VARIANT_ID="container-{arch}" HOME_URL="{GL_HOME_URL}" SUPPORT_URL="{GL_SUPPORT_URL}" BUG_REPORT_URL="{GL_BUG_REPORT_URL}" -GARDENLINUX_CNAME="container-amd64-{version}-{commit_hash}" -GARDENLINUX_FEATURES="_slim,base,container" +GARDENLINUX_CNAME="container" +GARDENLINUX_FEATURES="_archgrouped,_slim,base,container" GARDENLINUX_FEATURES_PLATFORMS="container" GARDENLINUX_FEATURES_ELEMENTS="base" -GARDENLINUX_FEATURES_FLAGS="_slim" +GARDENLINUX_FEATURES_FLAGS="_archgrouped,_slim" GARDENLINUX_PLATFORM="container" -GARDENLINUX_PLATFORM_VARIANT="" +GARDENLINUX_PLATFORM_VARIANT="{variant}" GARDENLINUX_VERSION="{version}" GARDENLINUX_COMMIT_ID="{commit_hash}" GARDENLINUX_COMMIT_ID_LONG="{commit_hash}" -""".strip() +""" + + return metadata.strip() diff --git a/tests/features/test_cname.py b/tests/features/test_cname.py index 3d173844..13b13b95 100644 --- a/tests/features/test_cname.py +++ b/tests/features/test_cname.py @@ -19,12 +19,12 @@ "metal_pxe", ), ( - "container-amd64", + "container", "container", ), ], ) -def test_cname_flavor(input_cname: str, expected_output: str) -> None: +def test_cname(input_cname: str, expected_output: str) -> None: """ Tests if cname returns the dict with expected features. @@ -32,19 +32,6 @@ def test_cname_flavor(input_cname: str, expected_output: str) -> None: features have changed since writing this test. In this case, update the expected output accordingly. You can print the output of cname so you have the dict in the expected format. """ - cname = CName(input_cname) - assert cname.flavor == expected_output - - -def test_cname_commit_id_setter() -> None: - """ - Tests cname setter for `commit_id` to verify a given ID before overwriting. - """ - cname = CName("container", arch="amd64", version="today", commit_hash="local") - - # Act / Assert - with pytest.raises( - RuntimeError, match="Commit hash given differs from commit ID already set" - ): - cname.commit_hash = "broken" + cname = CName(input_cname) + assert str(cname) == expected_output diff --git a/tests/features/test_cname_main.py b/tests/features/test_cname_main.py deleted file mode 100644 index 5a40c5fb..00000000 --- a/tests/features/test_cname_main.py +++ /dev/null @@ -1,159 +0,0 @@ -import logging -import sys -import types -from typing import Any, List, Tuple - -import networkx -import pytest - -import gardenlinux.features.cname_main as cname_main -from gardenlinux.features import Parser - - -def test_main_happy( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - """ - Test the "Happy Path" of the main() function. - """ - # Arrange - argv = ["prog", "--arch", "amd64", "--version", "1.0-abc123", "flav-amd64"] - monkeypatch.setattr(sys, "argv", argv) - - class FakeGraph: - def in_degree(self) -> List[Tuple[str, int]]: - return [("f1", 0)] - - edges = [("f1", "f2")] - - class FakeParser(Parser): - def __init__(self, *a: Any, **k: Any): - pass - - def filter(self, *a: Any, **k: Any) -> networkx.Graph: - return FakeGraph() - - @staticmethod - def sort_graph_nodes(graph: networkx.Graph) -> List[str]: - return ["f1", "f2"] - - monkeypatch.setattr(cname_main, "Parser", FakeParser) - - # Act - cname_main.main() - - # Assert - out = capsys.readouterr().out - assert "f1" in out - assert "amd64" in out - - -def test_main_version_from_file( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - """ - "Happy Path" test for grabbing the version and commit id from file in main(). - """ - # Arrange - argv = ["prog", "--arch", "amd64", "flav-amd64"] - monkeypatch.setattr(sys, "argv", argv) - - monkeypatch.setattr( - cname_main, - "get_version_and_commit_id_from_files", - lambda root: ("2.0", "abcdef12"), - ) - - class FakeParser(Parser): - def __init__(self, *a: Any, **k: Any): - pass - - def filter(self, *a: Any, **k: Any) -> networkx.Graph: - return types.SimpleNamespace(in_degree=lambda: [("f1", 0)], edges=[]) - - @staticmethod - def sort_graph_nodes(graph: networkx.Graph) -> List[str]: - return ["f1"] - - monkeypatch.setattr(cname_main, "Parser", FakeParser) - - # Act - cname_main.main() - - # Assert - assert "2.0-abcdef12" in capsys.readouterr().out - - -def test_cname_main_version_file_missing_warns( - monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture -) -> None: - """ - Check if a warning is logged when it fails to read version and commit id files. - - Specifically, this test simulates a scenario where the helper function - `get_version_and_commit_id_from_files` raises a RuntimeError, which would occur - if the expected version or commit files are missing or unreadable. - """ - # Arrange - argv = ["prog", "--arch", "amd64", "flav-amd64"] - monkeypatch.setattr(sys, "argv", argv) - - # Patch version fatch function to raise RuntimeError (Simulates missing files) - def raise_runtime(*args: Any, **kwargs: Any) -> None: - raise RuntimeError("missing") - - monkeypatch.setattr( - cname_main, "get_version_and_commit_id_from_files", raise_runtime - ) - - # Patch Parser for minimal valid graph - class FakeParser(Parser): - def __init__(self, *a: Any, **k: Any): - pass - - # Return object with in_degree method returning a node with zero dependencies - def filter(self, *a: Any, **k: Any) -> networkx.Graph: - return types.SimpleNamespace(in_degree=lambda: [("f1", 0)], edges=[]) - - @staticmethod - def sort_graph_nodes(graph: networkx.Graph) -> List[str]: - return ["f1"] - - monkeypatch.setattr(cname_main, "Parser", FakeParser) - - # Capture any logs with WARNING level - caplog.set_level(logging.WARNING) - - # Act - cname_main.main() - - # Assert - assert "Failed to parse version information" in caplog.text - - -def test_cname_main_invalid_cname_raises(monkeypatch: pytest.MonkeyPatch) -> None: - """ - Test if AssertionError is raised with an invalid or malformed cname. - """ - # Arrange - argv = ["prog", "--arch", "amd64", "--version", "1.0", "INVALID@NAME"] - monkeypatch.setattr(sys, "argv", argv) - - # Act / Assert - with pytest.raises(AssertionError): - cname_main.main() - - -def test_cname_main_missing_arch_in_cname_raises( - monkeypatch: pytest.MonkeyPatch, -) -> None: - """ - Test if an assertion error is raised when the arch argument is missing. - """ - # Arrange - argv = ["prog", "--version", "1.0", "flav"] - monkeypatch.setattr(sys, "argv", argv) - - # Act / Assert - with pytest.raises(AssertionError): - cname_main.main() diff --git a/tests/features/test_main.py b/tests/features/test_main.py index a0df4326..cdac5e58 100644 --- a/tests/features/test_main.py +++ b/tests/features/test_main.py @@ -1,16 +1,14 @@ import sys -import types from pathlib import Path -from tempfile import TemporaryDirectory -from typing import Any, List, Tuple +from typing import List, Optional import pytest import gardenlinux.features.__main__ as fema -from gardenlinux.features import CName +from gardenlinux.features import ArtifactBaseName from ..constants import GL_ROOT_DIR -from .constants import generate_container_amd64_release_metadata +from .constants import generate_container_release_metadata # ------------------------------- # Helper function tests @@ -40,26 +38,11 @@ class MockGraph: # Act / Assert with pytest.raises( - RuntimeError, match="Error while generating graph: Flavor is None!" + RuntimeError, match="Error while generating graph: CName is None!" ): fema.graph_as_mermaid_markup(None, MockGraph()) -def test_get_minimal_feature_set_filters() -> None: - # Arrange - class FakeGraph: - def in_degree(self) -> List[Tuple[str, int]]: - return [("a", 0), ("b", 1), ("c", 0)] - - graph = FakeGraph() - - # Act - result = fema.get_minimal_feature_set(graph) - - # Assert - assert result == {"a", "c"} - - def test_get_version_and_commit_from_file(tmp_path: Path) -> None: # Arrange commit_file = tmp_path / "COMMIT" @@ -68,191 +51,463 @@ def test_get_version_and_commit_from_file(tmp_path: Path) -> None: version_file.write_text("1.2.3\n") # Act - version, commit = fema.get_version_and_commit_id_from_files(str(tmp_path)) + version, commit = ArtifactBaseName.get_version_and_commit_id_from_files( + str(tmp_path) + ) # Arrange assert version == "1.2.3" assert commit == "abcdef12" -def test_get_version_missing_file_raises(tmp_path: Path) -> None: - # Arrange (one file only) - (tmp_path / "COMMIT").write_text("abcdef1234\n") - - # Act / Assert - with pytest.raises(RuntimeError): - fema.get_version_and_commit_id_from_files(str(tmp_path)) - - # ------------------------------- # Tests for main() # ------------------------------- -def test_main_prints_arch( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - # Arrange - argv = ["prog", "--arch", "amd64", "--cname", "flav", "--version", "1.0", "arch"] - monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) - # Act - fema.main() - # Assert - out = capsys.readouterr().out - assert "amd64" in out - - -def test_main_prints_container_name( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +@pytest.mark.parametrize( + "input_argv, monkeypatch_version, release_metadata, ignored_features, expected_output", + [ + ( + [ + "--arch", + "amd64", + "--cname", + "flav", + "--version", + "1.0", + "--commit", + "local", + "arch", + ], + False, + None, + "", + "amd64", + ), + ( + [ + "--arch", + "arm64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "arch", + ], + False, + generate_container_release_metadata("today", "local", "arm64"), + "", + "arm64", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container-pythonDev", + "artifact-base-name", + ], + True, + None, + "", + "container-pythonDev-amd64-1.2.3-abcdef12", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "artifact-base-name", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "container-amd64-today-local", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container-pythonDev", + "artifact-base-name", + ], + True, + None, + "_archgrouped", + "container-pythonDev-amd64-1.2.3-abcdef12", + ), + ( + ["--arch", "amd64", "--cname", "flav", "cname"], + True, + None, + "", + "flav", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "cname", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "container", + ), + ( + ["--arch", "amd64", "--cname", "flav", "commit-id"], + True, + None, + "", + "abcdef12", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "commit-id", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "local", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container-pythonDev", + "--version", + "1.0", + "--commit", + "local", + "container-name", + ], + True, + None, + "", + "container-python-dev", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "flav", + "--version", + "1.0", + "--commit", + "post1", + "container-tag", + ], + False, + None, + "", + "1-0-post1", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "elements"], + True, + None, + "", + "python,pythonDev,base", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "elements", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "base", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "features"], + True, + None, + "", + "python,pythonDev,_archgrouped,_slim,base,container", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "features"], + True, + None, + "_archgrouped", + "python,pythonDev,_slim,base,container", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "features", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "_archgrouped,_slim,base,container", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "features", + ], + False, + generate_container_release_metadata("today", "local"), + "_archgrouped", + "_slim,base,container", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "flags"], + True, + None, + "", + "_archgrouped,_slim", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "flags"], + True, + None, + "_archgrouped", + "_slim", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "flags", + ], + False, + generate_container_release_metadata("today", "local"), + "", + "_archgrouped,_slim", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "flavor"], + True, + None, + "", + "container-pythonDev-amd64", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "platform"], + True, + None, + "", + "container", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "platform", + ], + False, + generate_container_release_metadata( + "today", "local", variant="magicMachine" + ), + "", + "container", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "platforms"], + True, + None, + "", + "container", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "--version", + "today", + "--commit", + "local", + "platform-variant", + ], + False, + generate_container_release_metadata( + "today", "local", variant="magicMachine" + ), + "", + "magicMachine", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "version"], + True, + None, + "", + "1.2.3", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container-pythonDev", + "version_and_commit-id", + ], + True, + None, + "", + "1.2.3-abcdef12", + ), + ( + [ + "--arch", + "amd64", + "--cname", + "container", + "version_and_commit-id", + ], + True, + generate_container_release_metadata("1.2.3", "abcdef12"), + "", + "1.2.3-abcdef12", + ), + ( + ["--arch", "amd64", "--cname", "container-pythonDev", "versioned-flavor"], + True, + None, + "", + "container-pythonDev-amd64-1.2.3", + ), + ], +) +def test_main_prints_result( + input_argv: List[str], + monkeypatch_version: bool, + release_metadata: Optional[str], + ignored_features: Optional[str], + expected_output: str, + monkeypatch: pytest.MonkeyPatch, + capsys: pytest.CaptureFixture[str], + tmp_path: Path, ) -> None: # Arrange argv = [ - "prog", - "--arch", - "amd64", - "--cname", - "container-pythonDev", - "--version", - "1.0", - "container_name", - ] - monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) - - # Act - fema.main() - - # Assert - out = capsys.readouterr().out - assert "container-python-dev" in out + "gl-feature-parse", + "--feature-dir", + f"{GL_ROOT_DIR}/features", + ] + input_argv + if release_metadata: + os_release_file = Path(tmp_path, "os_release") -def test_main_prints_container_tag( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - # Arrange - argv = [ - "prog", - "--arch", - "amd64", - "--cname", - "flav", - "--version", - "1.0", - "--commit", - "~post1", - "container_tag", - ] - monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) - - # Act - fema.main() + with os_release_file.open("w") as fp: + fp.write(release_metadata) - # Assert - out = capsys.readouterr().out.strip() - assert "1-0-post1" == out + argv += [ + "--release-file", + str(os_release_file), + ] + if ignored_features: + argv += [ + "--ignore", + str(ignored_features), + ] -def test_main_prints_commit_id( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - # Arrange - argv = ["prog", "--arch", "amd64", "--cname", "flav", "commit_id"] monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr( - fema, - "Parser", - lambda *a, **kw: types.SimpleNamespace(filter=lambda *a, **k: None), - ) - # Patch get_version_and_commit_id_from_files - monkeypatch.setattr( - fema, "get_version_and_commit_id_from_files", lambda root: ("1.2.3", "abcdef12") - ) + # monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) + + if monkeypatch_version: + monkeypatch.setattr( + "gardenlinux.features.artifact_base_name.ArtifactBaseName.get_version_and_commit_id_from_files", + lambda root: ("1.2.3", "abcdef12"), + ) # Act fema.main() + # Assert captured = capsys.readouterr() - assert "abcdef12" == captured.out.strip() + assert captured.out.strip() == expected_output -def test_main_prints_flags_elements_platforms( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] +def test_get_version_missing_file_raises( + monkeypatch: pytest.MonkeyPatch, tmp_path: Path ) -> None: - # Arrange + # Arrange (one file only) + (tmp_path / "COMMIT").write_text("abcdef1234\n") + argv = [ "prog", "--arch", "amd64", "--cname", "flav", - "--version", - "1.0", - "flags", + "version", ] - monkeypatch.setattr(sys, "argv", argv) - - class FakeCName(CName): - def __init__(self, *a: Any, **k: Any): - CName.__init__(self, *a, **k) - self._feature_flags_cached = ["flag1"] - monkeypatch.setattr(fema, "CName", FakeCName) - - # Act - fema.main() - - # Assert - out = capsys.readouterr().out - assert "flag1" in out - - -def test_main_prints_version( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - # Arrange - argv = ["prog", "--arch", "amd64", "--cname", "flav", "version"] monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr( - fema, - "Parser", - lambda *a, **kw: types.SimpleNamespace(filter=lambda *a, **k: None), - ) - # Patch get_version_and_commit_id_from_files - monkeypatch.setattr( - fema, "get_version_and_commit_id_from_files", lambda root: ("1.2.3", "abcdef12") - ) - - # Act - fema.main() - - captured = capsys.readouterr() - assert "1.2.3" == captured.out.strip() - + monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) -def test_main_prints_version_and_commit_id( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - # Arrange - argv = ["prog", "--arch", "amd64", "--cname", "flav", "version_and_commit_id"] - monkeypatch.setattr(sys, "argv", argv) - monkeypatch.setattr( - fema, - "Parser", - lambda *a, **kw: types.SimpleNamespace(filter=lambda *a, **k: None), - ) - # Patch get_version_and_commit_id_from_files - monkeypatch.setattr( - fema, "get_version_and_commit_id_from_files", lambda root: ("1.2.3", "abcdef12") + # Act / Assert + assert ArtifactBaseName.get_version_and_commit_id_from_files(str(tmp_path)) == ( + None, + None, ) - # Act - fema.main() - - captured = capsys.readouterr() - assert "1.2.3-abcdef12" == captured.out.strip() + with pytest.raises(ValueError, match="Argument missing: version"): + fema.main() def test_main_requires_cname(monkeypatch: pytest.MonkeyPatch) -> None: @@ -261,7 +516,10 @@ def test_main_requires_cname(monkeypatch: pytest.MonkeyPatch) -> None: monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) # Act / Assert - with pytest.raises(SystemExit): + with pytest.raises( + ValueError, + match="Argument missing: At least one of artifact_base_name, cname, flavor or versioned_flavor", + ): fema.main() @@ -272,7 +530,7 @@ def test_main_cname_raises_missing_commit_id(monkeypatch: pytest.MonkeyPatch) -> "prog", "--cname", "flav", - "--default-arch", + "--arch", "amd64", "--version", "1.0", @@ -281,7 +539,7 @@ def test_main_cname_raises_missing_commit_id(monkeypatch: pytest.MonkeyPatch) -> monkeypatch.setattr(sys, "argv", argv) # Act / Assert - with pytest.raises(RuntimeError, match="Version and commit ID"): + with pytest.raises(ValueError, match="Argument missing: version"): fema.main() @@ -292,7 +550,7 @@ def test_main_raises_no_arch_no_default(monkeypatch: pytest.MonkeyPatch) -> None monkeypatch.setattr(sys, "argv", argv) # Act / Assert - with pytest.raises(RuntimeError, match="Architecture could not be determined"): + with pytest.raises(ValueError, match="Argument missing: arch"): fema.main() @@ -308,13 +566,13 @@ def test_main_raises_missing_commit_id( "flav", "--version", "1.0", - "version_and_commit_id", + "version_and_commit-id", ] monkeypatch.setattr(sys, "argv", argv) monkeypatch.setattr(fema, "Parser", lambda *a, **kw: None) # Act / Assert - with pytest.raises(RuntimeError, match="Commit ID not specified"): + with pytest.raises(ValueError, match="Argument missing: version"): fema.main() @@ -387,34 +645,3 @@ def test_main_with_exclude_cname_print_features( "sap,ssh,_fwcfg,_ignite,_legacy,_nopkg,_prod,_slim,base,server,cloud,kvm,multipath,iscsi,nvme,gardener" == captured ) - - -def test_cname_release_file( - monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture[str] -) -> None: - """ - Test validation between release metadata and arguments given - """ - # Arrange - with TemporaryDirectory() as tmpdir: - os_release_file = Path(tmpdir, "os_release") - - with os_release_file.open("w") as fp: - fp.write(generate_container_amd64_release_metadata("today", "local")) - - argv = [ - "prog", - "--cname", - "container-amd64-today-local", - "--release-file", - str(os_release_file), - "cname", - ] - monkeypatch.setattr(sys, "argv", argv) - - # Act / Assert - fema.main() - - # Assert - out = capsys.readouterr().out - assert "container-amd64-today-local" in out diff --git a/tests/features/test_metadata_main.py b/tests/features/test_metadata_main.py index b8f0fc69..9487c269 100644 --- a/tests/features/test_metadata_main.py +++ b/tests/features/test_metadata_main.py @@ -6,7 +6,7 @@ import gardenlinux.features.metadata_main as metadata_main -from .constants import generate_container_amd64_release_metadata +from .constants import generate_container_release_metadata def test_main_output( @@ -18,7 +18,7 @@ def test_main_output( # Arrange argv = [ "prog", - "--cname", + "--flavor", "container-amd64", "--version", "today", @@ -32,8 +32,8 @@ def test_main_output( metadata_main.main() # Assert - expected = generate_container_amd64_release_metadata("today", "local") - assert expected == capsys.readouterr().out.strip() + expected = generate_container_release_metadata("today", "local") + assert capsys.readouterr().out.strip() == expected def test_main_write( @@ -47,7 +47,7 @@ def test_main_write( os_release_file = Path(tmpdir, "os_release") argv = [ "prog", - "--cname", + "--flavor", "container-amd64", "--version", "today", @@ -63,35 +63,60 @@ def test_main_write( metadata_main.main() # Assert - expected = generate_container_amd64_release_metadata("today", "local") + expected = generate_container_release_metadata("today", "local") assert expected == os_release_file.open("r").read() -def test_main_validation(monkeypatch: pytest.MonkeyPatch) -> None: +def test_main_validation(monkeypatch: pytest.MonkeyPatch, tmp_path: Path) -> None: """ Test validation between release metadata and arguments given """ # Arrange - with TemporaryDirectory() as tmpdir: - os_release_file = Path(tmpdir, "os_release") + os_release_file = Path(tmp_path, "os_release") - with os_release_file.open("w") as fp: - fp.write(generate_container_amd64_release_metadata("today", "local")) + with os_release_file.open("w") as fp: + fp.write(generate_container_release_metadata("today", "local")) - argv = [ - "prog", - "--cname", - "base-python-amd64", - "--version", - "today", - "--commit", - "local", - "--release-file", - str(os_release_file), - "output-release-metadata", - ] - monkeypatch.setattr(sys, "argv", argv) + argv = [ + "prog", + "--flavor", + "base-python-amd64", + "--version", + "today", + "--commit", + "local", + "--release-file", + str(os_release_file), + "output-release-metadata", + ] + monkeypatch.setattr(sys, "argv", argv) + + # Act / Assert + with pytest.raises(RuntimeError): + metadata_main.main() + + +def test_main_version_missing_file_raises( + monkeypatch: pytest.MonkeyPatch, tmp_path: Path +) -> None: + # Arrange + (tmp_path / "COMMIT").write_text("abcdef1234\n") - # Act / Assert - with pytest.raises(RuntimeError): - metadata_main.main() + os_release_file = Path(tmp_path, "os_release") + + with os_release_file.open("w") as fp: + fp.write(generate_container_release_metadata("today", "local")) + + argv = [ + "prog", + "--flavor", + "base-python-amd64", + "--release-file", + str(os_release_file), + "output-release-metadata", + ] + monkeypatch.setattr(sys, "argv", argv) + + # Act / Assert + with pytest.raises(ValueError, match="Argument missing: version"): + metadata_main.main() diff --git a/tests/features/test_parser.py b/tests/features/test_parser.py index 7bb49fe3..adb9ffa0 100644 --- a/tests/features/test_parser.py +++ b/tests/features/test_parser.py @@ -1,4 +1,4 @@ -from typing import Any, Dict, List +from typing import Any, Dict, List, Tuple import pytest @@ -132,21 +132,36 @@ def test_parser_return_intersection_subset() -> None: assert result == ["a", "c"] -def test_get_flavor_from_feature_set() -> None: +def test_get_cname_from_feature_set() -> None: # Arrange sorted_features = ["base", "_hidden", "extra"] # Act - result = Parser.get_flavor_from_feature_set(sorted_features) + result = Parser.get_cname_from_feature_set(sorted_features) # Assert - assert result == "base_hidden-extra" + assert result == "base-extra_hidden" -def test_gget_flavor_from_feature_set_empty_raises() -> None: +def test_get_cname_from_feature_set_empty_raises() -> None: # get_flavor with empty iterable raises TypeError - with pytest.raises(TypeError): - Parser.get_flavor_from_feature_set([]) + with pytest.raises(ValueError): + Parser.get_cname_from_feature_set([]) + + +def test_get_minimal_feature_set_filters() -> None: + # Arrange + class FakeGraph: + def in_degree(self) -> List[Tuple[str, int]]: + return [("a", 0), ("b", 1), ("c", 0)] + + graph = FakeGraph() + + # Act + result = Parser.get_minimal_feature_set(graph) + + # Assert + assert result == {"a", "c"} def test_parser_subset_nomatch() -> None: diff --git a/tests/features/test_reproducibility.py b/tests/features/test_reproducibility.py index 7cc5cdd2..0a99d466 100644 --- a/tests/features/test_reproducibility.py +++ b/tests/features/test_reproducibility.py @@ -8,94 +8,94 @@ from gardenlinux.features.reproducibility.comparator import Comparator from gardenlinux.features.reproducibility.markdown_formatter import MarkdownFormatter -FLAVORS_MATRIX = { +CNAMES_MATRIX = { "include": [ - {"arch": "amd64", "flavor": "ali-gardener_prod"}, - {"arch": "amd64", "flavor": "aws-gardener_fips_prod"}, - {"arch": "amd64", "flavor": "aws-gardener_prod"}, - {"arch": "amd64", "flavor": "aws-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "aws-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "aws-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "azure-gardener_prod"}, - {"arch": "amd64", "flavor": "azure-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "azure-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "azure-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "baremetal-capi"}, - {"arch": "amd64", "flavor": "baremetal-gardener_prod"}, - {"arch": "amd64", "flavor": "baremetal-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "baremetal-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "baremetal-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "baremetal-gardener_pxe"}, - {"arch": "amd64", "flavor": "baremetal-vhost"}, - {"arch": "amd64", "flavor": "baremetal_pxe"}, - {"arch": "amd64", "flavor": "container"}, - {"arch": "amd64", "flavor": "container-pythonDev"}, - {"arch": "amd64", "flavor": "gcp-gardener_prod"}, - {"arch": "amd64", "flavor": "gcp-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "gcp-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "gcp-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "gdch-gardener_prod"}, - {"arch": "amd64", "flavor": "kvm-gardener_prod"}, - {"arch": "amd64", "flavor": "kvm-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "kvm-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "kvm-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "lima"}, - {"arch": "amd64", "flavor": "openstack-gardener_prod"}, - {"arch": "amd64", "flavor": "openstack-gardener_prod_tpm2_trustedboot"}, - {"arch": "amd64", "flavor": "openstack-gardener_prod_trustedboot"}, - {"arch": "amd64", "flavor": "openstack-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "openstack-metal-gardener_prod"}, - {"arch": "amd64", "flavor": "openstack-metal-gardener_prod_usi"}, - {"arch": "amd64", "flavor": "vmware-gardener_prod"}, - {"arch": "arm64", "flavor": "aws-gardener_fips_prod"}, - {"arch": "arm64", "flavor": "aws-gardener_prod"}, - {"arch": "arm64", "flavor": "aws-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "aws-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "aws-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "azure-gardener_prod"}, - {"arch": "arm64", "flavor": "azure-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "azure-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "azure-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "baremetal-capi"}, - {"arch": "arm64", "flavor": "baremetal-gardener_prod"}, - {"arch": "arm64", "flavor": "baremetal-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "baremetal-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "baremetal-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "baremetal-gardener_pxe"}, - {"arch": "arm64", "flavor": "baremetal-vhost"}, - {"arch": "arm64", "flavor": "baremetal_pxe"}, - {"arch": "arm64", "flavor": "container"}, - {"arch": "arm64", "flavor": "container-pythonDev"}, - {"arch": "arm64", "flavor": "gcp-gardener_prod"}, - {"arch": "arm64", "flavor": "gcp-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "gcp-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "gcp-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "gdch-gardener_prod"}, - {"arch": "arm64", "flavor": "kvm-gardener_prod"}, - {"arch": "arm64", "flavor": "kvm-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "kvm-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "kvm-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "lima"}, - {"arch": "arm64", "flavor": "openstack-gardener_prod"}, - {"arch": "arm64", "flavor": "openstack-gardener_prod_tpm2_trustedboot"}, - {"arch": "arm64", "flavor": "openstack-gardener_prod_trustedboot"}, - {"arch": "arm64", "flavor": "openstack-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "openstack-metal-gardener_prod"}, - {"arch": "arm64", "flavor": "openstack-metal-gardener_prod_usi"}, - {"arch": "arm64", "flavor": "vmware-gardener_prod"}, + {"arch": "amd64", "cname": "ali-gardener_prod"}, + {"arch": "amd64", "cname": "aws-gardener_fips_prod"}, + {"arch": "amd64", "cname": "aws-gardener_prod"}, + {"arch": "amd64", "cname": "aws-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "aws-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "aws-gardener_prod_usi"}, + {"arch": "amd64", "cname": "azure-gardener_prod"}, + {"arch": "amd64", "cname": "azure-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "azure-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "azure-gardener_prod_usi"}, + {"arch": "amd64", "cname": "baremetal-capi"}, + {"arch": "amd64", "cname": "baremetal-gardener_prod"}, + {"arch": "amd64", "cname": "baremetal-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "baremetal-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "baremetal-gardener_prod_usi"}, + {"arch": "amd64", "cname": "baremetal-gardener_pxe"}, + {"arch": "amd64", "cname": "baremetal-vhost"}, + {"arch": "amd64", "cname": "baremetal_pxe"}, + {"arch": "amd64", "cname": "container"}, + {"arch": "amd64", "cname": "container-pythonDev"}, + {"arch": "amd64", "cname": "gcp-gardener_prod"}, + {"arch": "amd64", "cname": "gcp-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "gcp-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "gcp-gardener_prod_usi"}, + {"arch": "amd64", "cname": "gdch-gardener_prod"}, + {"arch": "amd64", "cname": "kvm-gardener_prod"}, + {"arch": "amd64", "cname": "kvm-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "kvm-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "kvm-gardener_prod_usi"}, + {"arch": "amd64", "cname": "lima"}, + {"arch": "amd64", "cname": "openstack-gardener_prod"}, + {"arch": "amd64", "cname": "openstack-gardener_prod_tpm2_trustedboot"}, + {"arch": "amd64", "cname": "openstack-gardener_prod_trustedboot"}, + {"arch": "amd64", "cname": "openstack-gardener_prod_usi"}, + {"arch": "amd64", "cname": "openstack-metal-gardener_prod"}, + {"arch": "amd64", "cname": "openstack-metal-gardener_prod_usi"}, + {"arch": "amd64", "cname": "vmware-gardener_prod"}, + {"arch": "arm64", "cname": "aws-gardener_fips_prod"}, + {"arch": "arm64", "cname": "aws-gardener_prod"}, + {"arch": "arm64", "cname": "aws-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "aws-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "aws-gardener_prod_usi"}, + {"arch": "arm64", "cname": "azure-gardener_prod"}, + {"arch": "arm64", "cname": "azure-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "azure-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "azure-gardener_prod_usi"}, + {"arch": "arm64", "cname": "baremetal-capi"}, + {"arch": "arm64", "cname": "baremetal-gardener_prod"}, + {"arch": "arm64", "cname": "baremetal-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "baremetal-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "baremetal-gardener_prod_usi"}, + {"arch": "arm64", "cname": "baremetal-gardener_pxe"}, + {"arch": "arm64", "cname": "baremetal-vhost"}, + {"arch": "arm64", "cname": "baremetal_pxe"}, + {"arch": "arm64", "cname": "container"}, + {"arch": "arm64", "cname": "container-pythonDev"}, + {"arch": "arm64", "cname": "gcp-gardener_prod"}, + {"arch": "arm64", "cname": "gcp-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "gcp-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "gcp-gardener_prod_usi"}, + {"arch": "arm64", "cname": "gdch-gardener_prod"}, + {"arch": "arm64", "cname": "kvm-gardener_prod"}, + {"arch": "arm64", "cname": "kvm-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "kvm-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "kvm-gardener_prod_usi"}, + {"arch": "arm64", "cname": "lima"}, + {"arch": "arm64", "cname": "openstack-gardener_prod"}, + {"arch": "arm64", "cname": "openstack-gardener_prod_tpm2_trustedboot"}, + {"arch": "arm64", "cname": "openstack-gardener_prod_trustedboot"}, + {"arch": "arm64", "cname": "openstack-gardener_prod_usi"}, + {"arch": "arm64", "cname": "openstack-metal-gardener_prod"}, + {"arch": "arm64", "cname": "openstack-metal-gardener_prod_usi"}, + {"arch": "arm64", "cname": "vmware-gardener_prod"}, ] } -BARE_FLAVORS_MATRIX = { +BARE_CNAMES_MATRIX = { "include": [ - {"arch": "amd64", "flavor": "bare-libc"}, - {"arch": "amd64", "flavor": "bare-nodejs"}, - {"arch": "amd64", "flavor": "bare-python"}, - {"arch": "amd64", "flavor": "bare-sapmachine"}, - {"arch": "arm64", "flavor": "bare-libc"}, - {"arch": "arm64", "flavor": "bare-nodejs"}, - {"arch": "arm64", "flavor": "bare-python"}, - {"arch": "arm64", "flavor": "bare-sapmachine"}, + {"arch": "amd64", "cname": "bare-libc"}, + {"arch": "amd64", "cname": "bare-nodejs"}, + {"arch": "amd64", "cname": "bare-python"}, + {"arch": "amd64", "cname": "bare-sapmachine"}, + {"arch": "arm64", "cname": "bare-libc"}, + {"arch": "arm64", "cname": "bare-nodejs"}, + {"arch": "arm64", "cname": "bare-python"}, + {"arch": "arm64", "cname": "bare-sapmachine"}, ] } @@ -110,16 +110,16 @@ def test_formatter(i: str) -> None: if nightly_stats.is_file(): formatter = MarkdownFormatter( - FLAVORS_MATRIX, - BARE_FLAVORS_MATRIX, + CNAMES_MATRIX, + BARE_CNAMES_MATRIX, diff_files.joinpath(i), gardenlinux_root=str(gardenlinux_root), nightly_stats=nightly_stats, ) else: formatter = MarkdownFormatter( - FLAVORS_MATRIX, - BARE_FLAVORS_MATRIX, + CNAMES_MATRIX, + BARE_CNAMES_MATRIX, diff_files.joinpath(i), gardenlinux_root=str(gardenlinux_root), ) @@ -143,8 +143,8 @@ def test_formatter_main( str(gardenlinux_root.joinpath("features")), "--diff-dir", str(diff_files.joinpath(i)), - json.dumps(FLAVORS_MATRIX), - json.dumps(BARE_FLAVORS_MATRIX), + json.dumps(CNAMES_MATRIX), + json.dumps(BARE_CNAMES_MATRIX), ] if nightly_stats.is_file(): diff --git a/tests/github/test_main.py b/tests/github/test_main.py index 981e4499..5f9e9480 100644 --- a/tests/github/test_main.py +++ b/tests/github/test_main.py @@ -147,9 +147,9 @@ def test_script_upload_needs_github_token( "gardenlinux", "--repo", "gardenlinux", - "--release_id", + "--release-id", TEST_GARDENLINUX_RELEASE_MINOR, - "--file_path", + "--file", str(artifact_for_upload), "--dry-run", ], @@ -174,8 +174,7 @@ def test_script_parse_args_upload_command_required_args( captured = capfd.readouterr() assert ( - "the following arguments are required: --release_id, --file_path" - in captured.err + "the following arguments are required: --release-id, --file" in captured.err ), "Expected help message on missing arguments for 'upload' command" @@ -208,9 +207,9 @@ def test_script_upload_dry_run( "gardenlinux", "--repo", "gardenlinux", - "--release_id", + "--release-id", TEST_GARDENLINUX_RELEASE_MINOR, - "--file_path", + "--file", str(artifact_for_upload), "--dry-run", ], @@ -267,9 +266,9 @@ def test_script_upload_inaccessible_file( "gardenlinux", "--repo", "gardenlinux", - "--release_id", + "--release-id", TEST_GARDENLINUX_RELEASE_MINOR, - "--file_path", + "--file", str(artifact_for_upload), ], ) @@ -319,9 +318,9 @@ def test_script_upload( "gardenlinux", "--repo", "gardenlinux", - "--release_id", + "--release-id", TEST_GARDENLINUX_RELEASE_MINOR, - "--file_path", + "--file", str(artifact_for_upload), ], ) diff --git a/tests/oci/test_image_manifest.py b/tests/oci/test_image_manifest.py index 4ac89691..3d744c52 100644 --- a/tests/oci/test_image_manifest.py +++ b/tests/oci/test_image_manifest.py @@ -22,10 +22,16 @@ def test_ImageManifest_arch() -> None: def test_ImageManifest_cname() -> None: # Arrange - cname = "container-amd64-today-local" + arch = "amd64" + cname = "container" empty_manifest = ImageManifest() - manifest = ImageManifest(annotations={ImageManifest.ANNOTATION_CNAME_KEY: cname}) + manifest = ImageManifest( + annotations={ + ImageManifest.ANNOTATION_CNAME_KEY: cname, + ImageManifest.ANNOTATION_ARCH_KEY: arch, + } + ) # Assert with pytest.raises(RuntimeError): @@ -58,18 +64,25 @@ def test_ImageManifest_feature_set() -> None: def test_ImageManifest_flavor() -> None: # Arrange - flavor = "container" - cname = f"{flavor}-amd64-today-local" + arch = "amd64" + cname = "container" + flavor = f"{cname}-{arch}" empty_manifest = ImageManifest() - manifest = ImageManifest(annotations={ImageManifest.ANNOTATION_CNAME_KEY: cname}) + manifest = ImageManifest( + annotations={ + ImageManifest.ANNOTATION_CNAME_KEY: cname, + ImageManifest.ANNOTATION_ARCH_KEY: arch, + } + ) # Assert with pytest.raises(RuntimeError): - assert empty_manifest.flavor == flavor + assert empty_manifest.cname == cname - empty_manifest.cname = cname - assert empty_manifest.flavor == flavor + empty_manifest.flavor = flavor + assert empty_manifest.cname == cname + assert empty_manifest.arch == arch assert manifest.flavor == flavor diff --git a/tests/oci/test_main.py b/tests/oci/test_main.py index 27727684..234b1dbd 100644 --- a/tests/oci/test_main.py +++ b/tests/oci/test_main.py @@ -6,13 +6,13 @@ import pytest import gardenlinux.oci.__main__ as oci_main -from gardenlinux.oci import Container, Podman +from gardenlinux.oci import Podman, Repository from gardenlinux.oci.podman_context import PodmanContext from ..constants import REGISTRY, REPO_NAME, TEST_DATA_DIR -def test_main_build_container( +def test_main_build_image( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: monkeypatch.setattr( @@ -20,18 +20,17 @@ def test_main_build_container( "argv", [ "__main__.py", - "build-container", + "build-image", "--dir", f"{TEST_DATA_DIR}/oci/build", - "--container", + "--repository", "container-test", "--tag", "latest", ], ) - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() captured = capsys.readouterr() image_id = captured.out.strip() @@ -46,7 +45,7 @@ def test_main_build_container( podman.images.remove(image) -def test_main_build_container_and_save_as_oci_archive( +def test_main_build_image_and_save_as_oci_archive( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: with TemporaryDirectory() as tmpdir: @@ -55,14 +54,14 @@ def test_main_build_container_and_save_as_oci_archive( "argv", [ "__main__.py", - "build-container", + "build-image", "--dir", f"{TEST_DATA_DIR}/oci/build", - "--container", + "--repository", "container-test", "--tag", "latest", - "--oci_archive", + "--oci-archive", f"{tmpdir}/archive.oci", ], ) @@ -70,8 +69,7 @@ def test_main_build_container_and_save_as_oci_archive( image_id = None try: - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() captured = capsys.readouterr() image_id = captured.out.strip() @@ -84,7 +82,7 @@ def test_main_build_container_and_save_as_oci_archive( podman.images.remove(image) -def test_main_load_container( +def test_main_load_image( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: with PodmanContext() as podman_context, TemporaryDirectory() as tmpdir: @@ -102,14 +100,13 @@ def test_main_load_container( "argv", [ "__main__.py", - "load-container", - "--oci_archive", + "load-image", + "--oci-archive", f"{tmpdir}/archive.oci", ], ) - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() captured = capsys.readouterr() image_id_exported = captured.out.strip() @@ -121,7 +118,7 @@ def test_main_load_container( podman_context.images.remove(image) -def test_main_load_containers_from_directory( +def test_main_load_images_from_directory( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: with PodmanContext() as podman_context, TemporaryDirectory() as tmpdir: @@ -139,14 +136,13 @@ def test_main_load_containers_from_directory( "argv", [ "__main__.py", - "load-containers-from-directory", + "load-images-from-directory", "--dir", f"{tmpdir}", ], ) - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() captured = capsys.readouterr() result = json.loads(captured.out) @@ -161,7 +157,7 @@ def test_main_load_containers_from_directory( @pytest.mark.usefixtures("zot_session") -def test_main_push_container( +def test_main_push_image( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: with PodmanContext() as podman_context, TemporaryDirectory(): @@ -178,30 +174,28 @@ def test_main_push_container( "argv", [ "__main__.py", - "push-container", - "--container", + "push-image", + "--repository", image_id, "--destination", f"docker://{REGISTRY}/{REPO_NAME}/kidden:latest", "--insecure", - "true", ], ) - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() - container = Container( + repository = Repository( f"http://{REGISTRY}/{REPO_NAME}/kidden:latest", insecure=True ) # Assert - the following read would fail if push has not been successful - _ = container.read_manifest() + _ = repository.read_manifest() finally: if image_built is not None: podman_context.images.remove(image_built) -def test_main_tag_container( +def test_main_tag_image( monkeypatch: pytest.MonkeyPatch, capsys: pytest.CaptureFixture ) -> None: with PodmanContext() as podman_context, TemporaryDirectory(): @@ -218,20 +212,19 @@ def test_main_tag_container( "argv", [ "__main__.py", - "tag-container", - "--container", + "tag-image", + "--repository", image_id, - "--additional_tag", + "--additional-tag", "latest", - "--additional_tag", + "--additional-tag", "test:latest", - "--additional_tag", + "--additional-tag", "localhost/kidden:latest", ], ) - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() image = podman_context.images.get(image_id) @@ -244,7 +237,7 @@ def test_main_tag_container( podman_context.images.remove(image, force=True) -def test_main_save_container(monkeypatch: pytest.MonkeyPatch) -> None: +def test_main_save_image(monkeypatch: pytest.MonkeyPatch) -> None: with PodmanContext() as podman, TemporaryDirectory() as tmpdir: image_id = Podman().build( f"{TEST_DATA_DIR}/oci/build", oci_tag="container-test:latest", podman=podman @@ -255,19 +248,18 @@ def test_main_save_container(monkeypatch: pytest.MonkeyPatch) -> None: "argv", [ "__main__.py", - "save-container", - "--container", + "save-image", + "--repository", "container-test:latest", "--tag", "localhost/container-test:latest", - "--oci_archive", + "--oci-archive", f"{tmpdir}/archive.oci", ], ) try: - with pytest.raises(SystemExit, match="0"): - oci_main.main() + oci_main.main() assert Path(tmpdir, "archive.oci").exists() finally: diff --git a/tests/oci/test_oci.py b/tests/oci/test_oci.py index 50c50af2..1a3179d9 100644 --- a/tests/oci/test_oci.py +++ b/tests/oci/test_oci.py @@ -3,19 +3,19 @@ from typing import Any, List, Optional, Tuple import pytest -from click.testing import CliRunner from oras.client import OrasClient from oras.provider import Registry sys.path.append("src") -from gardenlinux.oci.__main__ import cli as gl_oci +from gardenlinux.oci import ImageManifest +from gardenlinux.oci.__main__ import main as gl_oci from ..constants import ( - CONTAINER_NAME_ZOT_EXAMPLE, GARDENLINUX_ROOT_DIR_EXAMPLE, REGISTRY, REGISTRY_URL, + REPOSITORY_NAME_ZOT_EXAMPLE, TEST_ARCHITECTURES, TEST_COMMIT, TEST_FEATURE_SET, @@ -27,124 +27,118 @@ def push_manifest( - runner: CliRunner, + monkeypatch: pytest.MonkeyPatch, version: str, arch: str, cname: str, additional_tags: Optional[List[str]] = None, -) -> bool: +) -> None: """Push manifest to registry and return success status""" print(f"Pushing manifest for {cname} {arch}") - cmd = [ + args = [ + "gl-oci", "push-manifest", - "--container", - CONTAINER_NAME_ZOT_EXAMPLE, - "--version", - version, - "--arch", - arch, + "--repository", + REPOSITORY_NAME_ZOT_EXAMPLE, "--cname", cname, + "--arch", + arch, + "--version", + version, + "--commit", + TEST_COMMIT, "--dir", GARDENLINUX_ROOT_DIR_EXAMPLE, - "--insecure", - "True", - "--cosign_file", + "--cosign-file", "digest", - "--manifest_file", + "--manifest-file", "manifests/manifest.json", + "--insecure", ] if additional_tags: for tag in additional_tags: - cmd.extend(["--additional_tag", tag]) + args.extend(["--additional-tag", tag]) - try: - result = runner.invoke( - gl_oci, - cmd, - catch_exceptions=False, - ) - print(f"Push manifest output: {result.output}") - return result.exit_code == 0 - except Exception as e: - print(f"Error during push manifest: {str(e)}") - return False + monkeypatch.setattr( + sys, + "argv", + args, + ) + + gl_oci() def push_manifest_tags( - runner: CliRunner, + monkeypatch: pytest.MonkeyPatch, version: str, arch: str, cname: str, tags: Optional[List[str]] = None, -) -> bool: +) -> None: """Push manifest to registry and return success status""" print(f"Pushing manifest for {cname} {arch}") - cmd = [ + args = [ + "gl-oci", "push-manifest-tags", - "--container", - CONTAINER_NAME_ZOT_EXAMPLE, - "--version", - version, - "--arch", - arch, + "--repository", + REPOSITORY_NAME_ZOT_EXAMPLE, "--cname", cname, + "--arch", + arch, + "--version", + version, + "--commit", + TEST_COMMIT, "--insecure", - "True", ] if tags: for tag in tags: - cmd.extend(["--tag", tag]) + args.extend(["--tag", tag]) - try: - result = runner.invoke( - gl_oci, - cmd, - catch_exceptions=False, - ) - print(f"Push manifest tags output: {result.output}") - return result.exit_code == 0 - except Exception as e: - print(f"Error during push manifest tags: {str(e)}") - return False + monkeypatch.setattr( + sys, + "argv", + args, + ) + + gl_oci() def update_index( - runner: CliRunner, version: str, additional_tags: Optional[List[str]] = None -) -> bool: + monkeypatch: pytest.MonkeyPatch, + version: str, + additional_tags: Optional[List[str]] = None, +) -> None: """Update index in registry and return success status""" print("Updating index") - cmd = [ + args = [ + "gl-oci", "push-index-from-directory", "--index", - CONTAINER_NAME_ZOT_EXAMPLE, + REPOSITORY_NAME_ZOT_EXAMPLE, "--index-tag", version, "--insecure", - "True", ] if additional_tags: for tag in additional_tags: - cmd.extend(["--additional_tag", tag]) + args.extend(["--additional-tag", tag]) - try: - result = runner.invoke( - gl_oci, - cmd, - catch_exceptions=False, - ) - print(f"Update index output: {result.output}") - return result.exit_code == 0 - except Exception as e: - print(f"Error during update index: {str(e)}") - return False + monkeypatch.setattr( + sys, + "argv", + args, + ) + + gl_oci() def get_catalog(client: OrasClient) -> List[Any]: @@ -223,22 +217,47 @@ def verify_combined_tag_manifest( assert "annotations" in manifest, "Manifest should contain annotations" annotations = manifest.get("annotations", {}) + assert annotations.get("architecture") == arch, ( f"Manifest should have architecture {arch}" ) - assert annotations.get("cname") == cname, f"Manifest should have cname {cname}" - assert annotations.get("version") == version, ( + + assert annotations.get(ImageManifest.ANNOTATION_CNAME_KEY) == cname, ( + f"Manifest should have cname {cname}" + ) + + if feature_set: + assert ( + annotations.get(ImageManifest.ANNOTATION_FEATURE_SET_KEY) == feature_set + ), f"Manifest should have feature set {feature_set}" + + assert annotations.get(ImageManifest.ANNOTATION_VERSION_KEY) == version, ( f"Manifest should have version {version}" ) + if commit: + assert annotations.get(ImageManifest.ANNOTATION_COMMIT_KEY) == commit, ( + f"Manifest should have commit {commit}" + ) + + # Deprecated annotations + if feature_set: assert annotations.get("feature_set") == feature_set, ( - f"Manifest should have feature_set {feature_set}" + f"Manifest should have deprecated feature set {feature_set}" ) + assert annotations.get("version") == version, ( + f"Manifest should have deprecated version {version}" + ) + if commit: + assert annotations.get("cname") == f"{cname}-{arch}-{version}-{commit}", ( + f"Manifest should have deprecated cname {cname}" + ) + assert annotations.get("commit") == commit, ( - f"Manifest should have commit {commit}" + f"Manifest should have deprecated commit {commit}" ) @@ -339,11 +358,11 @@ def test_push_manifest_and_index( cname: str, additional_tags_index: List[str], additional_tags_manifest: List[str], + monkeypatch: pytest.MonkeyPatch, ) -> None: print(f"\n\n=== Starting test for {cname} {arch} {version} ===") - runner = CliRunner() repo_name = "gardenlinux-example" - combined_tag = f"{version}-{cname}-{arch}" + combined_tag = f"{version}-{cname}-{arch}-{version}-{TEST_COMMIT}-{arch}" post_push_manifest_tags = [] @@ -352,20 +371,12 @@ def test_push_manifest_and_index( post_push_manifest_tags = additional_tags_manifest additional_tags_manifest = [] - push_successful = push_manifest( - runner, version, arch, cname, additional_tags_manifest - ) - assert push_successful, "Manifest push should succeed" + push_manifest(monkeypatch, version, arch, cname, additional_tags_manifest) if len(post_push_manifest_tags) > 0: - push_successful = push_manifest_tags( - runner, version, arch, cname, post_push_manifest_tags - ) - assert push_successful, "Manifest tags push should succeed" + push_manifest_tags(monkeypatch, version, arch, cname, post_push_manifest_tags) - if push_successful: - update_index_successful = update_index(runner, version, additional_tags_index) - assert update_index_successful, "Index update should succeed" + update_index(monkeypatch, version, additional_tags_index) # Verify registry contents print(f"\n=== Verifying registry for {cname} {arch} {version} ===") diff --git a/tests/oci/test_podman.py b/tests/oci/test_podman.py index c0688adc..71e0ffc1 100644 --- a/tests/oci/test_podman.py +++ b/tests/oci/test_podman.py @@ -21,7 +21,7 @@ def test_podman_tag_list( try: podman.tag_list( image_id, - Podman.get_container_tag_list("container-test", ["a", "b", "c"]), + Podman.get_image_tag_list("container-test", ["a", "b", "c"]), ) image = podman_context.images.get(image_id) diff --git a/tests/oci/test_container.py b/tests/oci/test_repository.py similarity index 56% rename from tests/oci/test_container.py rename to tests/oci/test_repository.py index deecdc61..d03865f4 100644 --- a/tests/oci/test_container.py +++ b/tests/oci/test_repository.py @@ -5,13 +5,13 @@ from requests import Response from requests.exceptions import HTTPError -from gardenlinux.oci import Container +from gardenlinux.oci import Repository -from ..constants import CONTAINER_NAME_ZOT_EXAMPLE, REGISTRY, TEST_COMMIT, TEST_VERSION +from ..constants import REGISTRY, REPOSITORY_NAME_ZOT_EXAMPLE, TEST_COMMIT, TEST_VERSION -@pytest.fixture(name="Container_login_403") -def patch__Container_login_403(monkeypatch: pytest.MonkeyPatch) -> None: +@pytest.fixture(name="Repository_login_403") +def patch_Repository_login_403(monkeypatch: pytest.MonkeyPatch) -> None: """Patch `login()` to return HTTP 403. `docker.errors.APIError` extends from `requests.exceptions.HTTPError` as well.""" def login_403(*args: Any, **kwargs: Any) -> None: @@ -19,11 +19,11 @@ def login_403(*args: Any, **kwargs: Any) -> None: response.status_code = 403 raise HTTPError("403 Forbidden", response=response) - monkeypatch.setattr(Container, "login", login_403) + monkeypatch.setattr(Repository, "login", login_403) -@pytest.fixture(name="Container_read_or_generate_403") -def patch__Container_read_or_generate_403(monkeypatch: pytest.MonkeyPatch) -> None: +@pytest.fixture(name="Repository_read_or_generate_403") +def patch_Repository_read_or_generate_403(monkeypatch: pytest.MonkeyPatch) -> None: """Patch `read_or_generate_manifest()` to return HTTP 403.""" def read_or_generate_403(*args: Any, **kwargs: Any) -> None: @@ -31,16 +31,18 @@ def read_or_generate_403(*args: Any, **kwargs: Any) -> None: response.status_code = 403 raise HTTPError("403 Forbidden", response=response) - monkeypatch.setattr(Container, "read_or_generate_manifest", read_or_generate_403) + monkeypatch.setattr(Repository, "read_or_generate_manifest", read_or_generate_403) @pytest.mark.usefixtures("zot_session") def test_manifest() -> None: """Verify a newly created manifest returns correct commit value.""" # Arrange - container = Container(f"{CONTAINER_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True) + repository = Repository( + f"{REPOSITORY_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True + ) - manifest = container.read_or_generate_manifest( + manifest = repository.read_or_generate_manifest( version=TEST_VERSION, commit=TEST_COMMIT ) @@ -49,46 +51,48 @@ def test_manifest() -> None: @pytest.mark.usefixtures("zot_session") -@pytest.mark.usefixtures("Container_read_or_generate_403") +@pytest.mark.usefixtures("Repository_read_or_generate_403") def test_manifest_403() -> None: - """Verify container calls raises exceptions for certain errors.""" + """Verify repository calls raises exceptions for certain errors.""" # Arrange - container = Container(f"{CONTAINER_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True) + repository = Repository( + f"{REPOSITORY_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True + ) with pytest.raises(HTTPError): - container.read_or_generate_manifest(version=TEST_VERSION, commit=TEST_COMMIT) + repository.read_or_generate_manifest(version=TEST_VERSION, commit=TEST_COMMIT) @pytest.mark.usefixtures("zot_session") def test_manifest_auth_token( monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture ) -> None: - """Verify container calls use login environment variables if defined.""" + """Verify repository calls use login environment variables if defined.""" with monkeypatch.context(): token = "test" monkeypatch.setenv("GL_CLI_REGISTRY_TOKEN", token) # Arrange - container = Container( - f"{CONTAINER_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True + repository = Repository( + f"{REPOSITORY_NAME_ZOT_EXAMPLE}:{TEST_VERSION}", insecure=True ) # Assert - assert container.auth.token == b64encode(bytes(token, "utf-8")).decode("utf-8") + assert repository.auth.token == b64encode(bytes(token, "utf-8")).decode("utf-8") @pytest.mark.usefixtures("zot_session") -@pytest.mark.usefixtures("Container_login_403") +@pytest.mark.usefixtures("Repository_login_403") def test_manifest_login_username_password( monkeypatch: pytest.MonkeyPatch, caplog: pytest.LogCaptureFixture ) -> None: - """Verify container calls use login environment variables if defined.""" + """Verify repository calls use login environment variables if defined.""" with monkeypatch.context(): monkeypatch.setenv("GL_CLI_REGISTRY_USERNAME", "test") monkeypatch.setenv("GL_CLI_REGISTRY_PASSWORD", "test") # Arrange - Container(f"{REGISTRY}/protected/test:{TEST_VERSION}", insecure=True) + Repository(f"{REGISTRY}/protected/test:{TEST_VERSION}", insecure=True) # Assert assert "Login error: 403 Forbidden" in caplog.text diff --git a/tests/s3/conftest.py b/tests/s3/conftest.py index 8ba1fa09..9219fd06 100644 --- a/tests/s3/conftest.py +++ b/tests/s3/conftest.py @@ -20,10 +20,10 @@ class S3Env: s3: S3ServiceResource bucket_name: str tmp_path: Path - cname: str + artifact_base_name: str -def make_cname( +def make_artifact_base_name( flavor: str = "container_trustedboot_usi", arch: str = "amd64", version: str = "1234.1", @@ -64,5 +64,5 @@ def s3_setup( monkeypatch.setattr("gardenlinux.s3.s3_artifacts.file_digest", dummy_digest) - cname = make_cname() - yield S3Env(s3, BUCKET_NAME, tmp_path, cname) + artifact_base_name = make_artifact_base_name() + yield S3Env(s3, BUCKET_NAME, tmp_path, artifact_base_name) diff --git a/tests/s3/constants.py b/tests/s3/constants.py index b8a06bf9..d63680fe 100644 --- a/tests/s3/constants.py +++ b/tests/s3/constants.py @@ -1,7 +1,8 @@ # -*- coding: utf-8 -*- RELEASE_DATA = """ -GARDENLINUX_CNAME="container_trustedboot_usi-amd64-1234.1" +VARIANT_ID="container_trustedboot_usi-amd64" +GARDENLINUX_CNAME="container_trustedboot_usi" GARDENLINUX_VERSION=1234.1 GARDENLINUX_COMMIT_ID="abc123lo" GARDENLINUX_COMMIT_ID_LONG="abc123long" diff --git a/tests/s3/test_main.py b/tests/s3/test_main.py index 7fa100ff..9051e084 100644 --- a/tests/s3/test_main.py +++ b/tests/s3/test_main.py @@ -22,7 +22,7 @@ "--path", "some/path", "download-artifacts-from-bucket", - "--cname", + "--artifact-base-name", "test-cname", ], "download_to_directory", @@ -37,7 +37,7 @@ "--path", "some/path", "upload-artifacts-to-bucket", - "--artifact-name", + "--artifact-base-name", "test-cname", ], "upload_from_directory", @@ -84,11 +84,11 @@ def test_main_with_expected_result( "--path", str(env.tmp_path), "upload-artifacts-to-bucket", - "--artifact-name", - env.cname, + "--artifact-base-name", + env.artifact_base_name, ], ): - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" release_path.write_text(RELEASE_DATA) s3m.main() diff --git a/tests/s3/test_s3_artifacts.py b/tests/s3/test_s3_artifacts.py index 9983c46f..abfd25be 100644 --- a/tests/s3/test_s3_artifacts.py +++ b/tests/s3/test_s3_artifacts.py @@ -37,19 +37,21 @@ def test_download_to_directory_success(s3_setup: S3Env) -> None: env = s3_setup bucket = env.s3.Bucket(env.bucket_name) - bucket.put_object(Key=f"meta/singles/{env.cname}", Body=b"metadata") - bucket.put_object(Key=f"objects/{env.cname}/file1", Body=b"data1") - bucket.put_object(Key=f"objects/{env.cname}/file2", Body=b"data2") + bucket.put_object(Key=f"meta/singles/{env.artifact_base_name}", Body=b"metadata") + bucket.put_object(Key=f"objects/{env.artifact_base_name}/file1", Body=b"data1") + bucket.put_object(Key=f"objects/{env.artifact_base_name}/file2", Body=b"data2") with TemporaryDirectory() as tmpdir: outdir = Path(tmpdir) # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.download_to_directory(env.cname, outdir) + artifacts.download_to_directory(env.artifact_base_name, outdir) # Assert - assert (outdir / f"{env.cname}.s3_metadata.yaml").read_bytes() == b"metadata" + assert ( + outdir / f"{env.artifact_base_name}.s3_metadata.yaml" + ).read_bytes() == b"metadata" assert (outdir / "file1").read_bytes() == b"data1" assert (outdir / "file2").read_bytes() == b"data2" @@ -64,7 +66,9 @@ def test_download_to_directory_invalid_path(s3_setup: S3Env) -> None: # Act / Assert with pytest.raises(RuntimeError): - artifacts.download_to_directory(env.cname, "/invalid/path/does/not/exist") + artifacts.download_to_directory( + env.artifact_base_name, "/invalid/path/does/not/exist" + ) def test_download_to_directory_non_pathlike_raises(s3_setup: S3Env) -> None: @@ -72,7 +76,7 @@ def test_download_to_directory_non_pathlike_raises(s3_setup: S3Env) -> None: env = s3_setup artifacts = S3Artifacts(env.bucket_name) with pytest.raises(RuntimeError): - artifacts.download_to_directory(env.cname, "nopath") + artifacts.download_to_directory(env.artifact_base_name, "nopath") def test_download_to_directory_no_metadata_raises(s3_setup: S3Env) -> None: @@ -83,8 +87,8 @@ def test_download_to_directory_no_metadata_raises(s3_setup: S3Env) -> None: # Act / Assert with TemporaryDirectory() as tmpdir: - with pytest.raises(IndexError): - artifacts.download_to_directory(env.cname, tmpdir) + with pytest.raises(RuntimeError): + artifacts.download_to_directory(env.artifact_base_name, tmpdir) def test_upload_from_directory_success(s3_setup: S3Env) -> None: @@ -94,30 +98,37 @@ def test_upload_from_directory_success(s3_setup: S3Env) -> None: # Arrange env = s3_setup - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" release_path.write_text(RELEASE_DATA) - for filename in [f"{env.cname}-file1", f"{env.cname}-file2", "container"]: + for filename in [ + f"{env.artifact_base_name}-file1", + f"{env.artifact_base_name}-file2", + "container", + ]: (env.tmp_path / filename).write_bytes(b"dummy content") # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) keys = [obj.key for obj in bucket.objects.all()] - assert f"objects/{env.cname}/{env.cname}-file1" in keys - assert f"objects/{env.cname}/{env.cname}-file2" in keys - assert f"meta/singles/{env.cname}" in keys + assert f"objects/{env.artifact_base_name}/{env.artifact_base_name}-file1" in keys + assert f"objects/{env.artifact_base_name}/{env.artifact_base_name}-file2" in keys + assert f"meta/singles/{env.artifact_base_name}" in keys - meta_obj = list(bucket.objects.filter(Prefix=f"meta/singles/{env.cname}"))[0] + meta_obj = list( + bucket.objects.filter(Prefix=f"meta/singles/{env.artifact_base_name}") + )[0] metadata = yaml.safe_load(meta_obj.get()["Body"].read()) assert metadata["require_uefi"] is True assert metadata["secureboot"] is True raw_tags_response = env.s3.meta.client.get_object_tagging( - Bucket=env.bucket_name, Key=f"objects/{env.cname}/{env.cname}-file1" + Bucket=env.bucket_name, + Key=f"objects/{env.artifact_base_name}/{env.artifact_base_name}-file1", ) tags = {tag["Key"]: tag["Value"] for tag in raw_tags_response["TagSet"]} assert tags["platform"] == "container" @@ -132,28 +143,34 @@ def test_upload_from_directory_with_delete(s3_setup: S3Env) -> None: bucket = env.s3.Bucket(env.bucket_name) # Arrange: create release and artifact files locally - release = env.tmp_path / f"{env.cname}.release" + release = env.tmp_path / f"{env.artifact_base_name}.release" release.write_text(RELEASE_DATA) - artifact = env.tmp_path / f"{env.cname}.kernel" + artifact = env.tmp_path / f"{env.artifact_base_name}.kernel" artifact.write_bytes(b"fake") # Arrange: put dummy existing objects to be deleted - bucket.put_object(Key=f"objects/{env.cname}/{artifact.name}", Body=b"old data") - bucket.put_object(Key=f"meta/singles/{env.cname}", Body=b"old metadata") + bucket.put_object( + Key=f"objects/{env.artifact_base_name}/{artifact.name}", Body=b"old data" + ) + bucket.put_object( + Key=f"meta/singles/{env.artifact_base_name}", Body=b"old metadata" + ) artifacts = S3Artifacts(env.bucket_name) # Act - artifacts.upload_from_directory(env.cname, env.tmp_path, delete_before_push=True) + artifacts.upload_from_directory( + env.artifact_base_name, env.tmp_path, delete_before_push=True + ) # Assert keys = [obj.key for obj in bucket.objects.all()] # The old key should no longer be present as old data (no duplicates) # but the new upload file key should exist (artifact uploaded) - assert f"objects/{env.cname}/{artifact.name}" in keys - assert f"meta/singles/{env.cname}" in keys + assert f"objects/{env.artifact_base_name}/{artifact.name}" in keys + assert f"meta/singles/{env.artifact_base_name}" in keys def test_upload_from_directory_invalid_dir_raises(s3_setup: S3Env) -> None: @@ -161,7 +178,7 @@ def test_upload_from_directory_invalid_dir_raises(s3_setup: S3Env) -> None: env = s3_setup artifacts = S3Artifacts(env.bucket_name) with pytest.raises(RuntimeError, match="invalid"): - artifacts.upload_from_directory(env.cname, "/invalid/path") + artifacts.upload_from_directory(env.artifact_base_name, "/invalid/path") def test_upload_from_directory_version_mismatch(s3_setup: S3Env) -> None: @@ -170,13 +187,13 @@ def test_upload_from_directory_version_mismatch(s3_setup: S3Env) -> None: """ # Arrange env = s3_setup - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" bad_data = RELEASE_DATA.replace("1234.1", "9999.9") release_path.write_text(bad_data) artifacts = S3Artifacts(env.bucket_name) # Act / Assert - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) def test_upload_from_directory_succeeds_because_of_release_file( @@ -199,7 +216,7 @@ def test_upload_from_directory_invalid_artifact_name(s3_setup: S3Env) -> None: """ # Arrange env = s3_setup - (env.tmp_path / f"{env.cname}.release").write_text(RELEASE_DATA) + (env.tmp_path / f"{env.artifact_base_name}.release").write_text(RELEASE_DATA) # Create "bad" artifact that does not start with cname bad_file = env.tmp_path / "no_match" @@ -208,14 +225,19 @@ def test_upload_from_directory_invalid_artifact_name(s3_setup: S3Env) -> None: artifacts = S3Artifacts(env.bucket_name) # Act - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) - assert len(list(bucket.objects.filter(Prefix=f"meta/singles/{env.cname}"))) == 1 + assert ( + len( + list(bucket.objects.filter(Prefix=f"meta/singles/{env.artifact_base_name}")) + ) + == 1 + ) -def test_upload_from_directory_invalid_release_file_with_valid_cname( +def test_upload_from_directory_beside_of_incomplete_release_file( s3_setup: S3Env, ) -> None: """ @@ -223,20 +245,25 @@ def test_upload_from_directory_invalid_release_file_with_valid_cname( """ # Arrange env = s3_setup - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" bad_data = RELEASE_DATA.replace( - "GARDENLINUX_FEATURES_PLATFORMS=", "GARDENLINUX_FEATURES_PLATFORMS_UNDEFINED=" + "GARDENLINUX_PLATFORM=", "GARDENLINUX_PLATFORM_UNDEFINED=" ) release_path.write_text(bad_data) artifacts = S3Artifacts(env.bucket_name) # Act - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) - assert len(list(bucket.objects.filter(Prefix=f"meta/singles/{env.cname}"))) == 1 + assert ( + len( + list(bucket.objects.filter(Prefix=f"meta/singles/{env.artifact_base_name}")) + ) + == 1 + ) def test_upload_from_directory_commit_mismatch(s3_setup: S3Env) -> None: @@ -245,13 +272,13 @@ def test_upload_from_directory_commit_mismatch(s3_setup: S3Env) -> None: """ # Arrange env = s3_setup - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" bad_data = RELEASE_DATA.replace("abc123", "wrong") release_path.write_text(bad_data) artifacts = S3Artifacts(env.bucket_name) # Act / Assert - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) def test_upload_from_directory_with_platform_variant(s3_setup: S3Env) -> None: @@ -260,20 +287,23 @@ def test_upload_from_directory_with_platform_variant(s3_setup: S3Env) -> None: """ # Arrange env = s3_setup - release_path = env.tmp_path / f"{env.cname}.release" + release_path = env.tmp_path / f"{env.artifact_base_name}.release" release_path.write_text( RELEASE_DATA.strip() + "\nGARDENLINUX_PLATFORM_VARIANT=test" ) + print(release_path.read_text()) # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) meta_obj = next( - o for o in bucket.objects.all() if o.key == f"meta/singles/{env.cname}" + o + for o in bucket.objects.all() + if o.key == f"meta/singles/{env.artifact_base_name}" ) metadata = yaml.safe_load(meta_obj.get()["Body"].read()) assert metadata["platform_variant"] == "test" @@ -283,21 +313,23 @@ def test_upload_directory_with_requirements_override(s3_setup: S3Env) -> None: """Ensure .requirements file values overide feature flag defaults.""" # Arrange env = s3_setup - (env.tmp_path / f"{env.cname}.release").write_text(RELEASE_DATA) - (env.tmp_path / f"{env.cname}.requirements").write_text( + (env.tmp_path / f"{env.artifact_base_name}.release").write_text(RELEASE_DATA) + (env.tmp_path / f"{env.artifact_base_name}.requirements").write_text( "uefi = false\nsecureboot = true\n" ) - artifact_file = env.tmp_path / f"{env.cname}-artifact" + artifact_file = env.tmp_path / f"{env.artifact_base_name}-artifact" artifact_file.write_bytes(b"abc") # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) meta_obj = next( - o for o in bucket.objects.all() if o.key == f"meta/singles/{env.cname}" + o + for o in bucket.objects.all() + if o.key == f"meta/singles/{env.artifact_base_name}" ) metadata = yaml.safe_load(meta_obj.get()["Body"].read()) assert metadata["require_uefi"] is False @@ -308,20 +340,22 @@ def test_upload_directory_with_publishing_group(s3_setup: S3Env) -> None: """A publishing_group value in the .requirements file is copied into the metadata.""" # Arrange env = s3_setup - (env.tmp_path / f"{env.cname}.release").write_text(RELEASE_DATA) - (env.tmp_path / f"{env.cname}.requirements").write_text( + (env.tmp_path / f"{env.artifact_base_name}.release").write_text(RELEASE_DATA) + (env.tmp_path / f"{env.artifact_base_name}.requirements").write_text( "arch = amd64\npublishing_group = container\n" ) - (env.tmp_path / f"{env.cname}-artifact").write_bytes(b"abc") + (env.tmp_path / f"{env.artifact_base_name}-artifact").write_bytes(b"abc") # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) meta_obj = next( - o for o in bucket.objects.all() if o.key == f"meta/singles/{env.cname}" + o + for o in bucket.objects.all() + if o.key == f"meta/singles/{env.artifact_base_name}" ) metadata = yaml.safe_load(meta_obj.get()["Body"].read()) assert metadata["publishing_group"] == "container" @@ -331,20 +365,22 @@ def test_upload_directory_without_publishing_group(s3_setup: S3Env) -> None: """An empty or absent publishing_group is not emitted, marking a standalone build.""" # Arrange env = s3_setup - (env.tmp_path / f"{env.cname}.release").write_text(RELEASE_DATA) - (env.tmp_path / f"{env.cname}.requirements").write_text( + (env.tmp_path / f"{env.artifact_base_name}.release").write_text(RELEASE_DATA) + (env.tmp_path / f"{env.artifact_base_name}.requirements").write_text( "arch = amd64\npublishing_group = \n" ) - (env.tmp_path / f"{env.cname}-artifact").write_bytes(b"abc") + (env.tmp_path / f"{env.artifact_base_name}-artifact").write_bytes(b"abc") # Act artifacts = S3Artifacts(env.bucket_name) - artifacts.upload_from_directory(env.cname, env.tmp_path) + artifacts.upload_from_directory(env.artifact_base_name, env.tmp_path) # Assert bucket = env.s3.Bucket(env.bucket_name) meta_obj = next( - o for o in bucket.objects.all() if o.key == f"meta/singles/{env.cname}" + o + for o in bucket.objects.all() + if o.key == f"meta/singles/{env.artifact_base_name}" ) metadata = yaml.safe_load(meta_obj.get()["Body"].read()) assert "publishing_group" not in metadata