From e04812f7e58333ee99432a98563c54951f5b1632 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bern=C3=A1t=20G=C3=A1bor?= Date: Sun, 25 Oct 2026 15:19:44 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=91=B7=20ci:=20unify=20release=20preparat?= =?UTF-8?q?ion?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move releases to the shared github-workflows 6.0.1 pipeline and release-creator 4.1.0. Preparation, App-authored commits and tags, distribution builds and release notes come from the shared Actions. The Sphinx changelog gets user-facing categories, stable release anchors and credits from commit authors and co-authors, and the PyPI description is rendered by hatch-fancy-pypi-readme. CONTRIBUTING explains that fragments carry no hand-written credit and that prepare runs release-creator contributors. The tag workflow builds the distributions in parallel with a read-only notes job, uploads to PyPI through OIDC, verifies the published digests and creates the GitHub Release with one call. Only writers can push or move tags, so the step that re-checked the tag before the GitHub Release is gone, as is the always-true pull_request condition on the news job. Distributions and notes pass between jobs by artifact ID. Tag runs never cancel; pull request and branch runs do. Nab writes pylock.toml from a [tool.nab] table, with a temporary upload cutoff exception for release-creator 4.1.0. A build group locks the hatchling backend with Cython and setuptools, because PyYAML has no CPython 3.15 wheel. The release-check group and the release-validate group, used only by the shared prepare validate job that 6.0.0 removed, go. Dependabot's pre-commit ecosystem and pre-commit.ci's quarterly autoupdate own hook updates, so the hook cooldown check and the managed hook pins go. Every workflow, job and step name starts with an emoji, which renames the required checks "Required checks pass" and "๐Ÿ“ฆ build". CodeQL moves from default setup to a committed advanced workflow on ubuntu-26.04 with the same languages, now running the security-extended suite and skipping tests. --- .github/dependabot.yaml | 10 + .github/workflows/check.yaml | 118 +- .github/workflows/codeql.yaml | 41 + .github/workflows/news.yaml | 32 + .github/workflows/prepare-release.yaml | 136 +- .github/workflows/release.yaml | 187 +- .github/workflows/upgrade-release-tools.yaml | 22 + .gitignore | 1 + .pre-commit-config.yaml | 40 +- CONTRIBUTING.md | 28 + docs/changelog.rst | 1099 +++++-- docs/changelog/.gitkeep | 0 docs/changelog/template.jinja2 | 13 - docs/conf.py | 34 + pylock.toml | 3047 ++++++++++++++++++ pyproject.toml | 73 +- 16 files changed, 4383 insertions(+), 498 deletions(-) create mode 100644 .github/workflows/codeql.yaml create mode 100644 .github/workflows/news.yaml create mode 100644 .github/workflows/upgrade-release-tools.yaml create mode 100644 docs/changelog/.gitkeep delete mode 100644 docs/changelog/template.jinja2 create mode 100644 pylock.toml diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml index 8eee825f..db9573ce 100644 --- a/.github/dependabot.yaml +++ b/.github/dependabot.yaml @@ -15,3 +15,13 @@ updates: - "*" cooldown: default-days: 7 + - package-ecosystem: "pre-commit" + directory: "/" + labels: + - dependencies + - skip news + schedule: + interval: "weekly" + day: "tuesday" + cooldown: + default-days: 7 diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index f98361d6..a851d29e 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -1,11 +1,11 @@ -name: check +name: ๐Ÿงช check on: workflow_dispatch: push: branches: ["main"] tags-ignore: ["**"] pull_request: - types: [opened, reopened, synchronize, labeled, unlabeled] + types: [opened, reopened, synchronize] schedule: - cron: "0 8 * * *" concurrency: @@ -15,7 +15,7 @@ permissions: contents: read jobs: test: - name: test ${{ matrix.py }} - ${{ matrix.os }} + name: ๐Ÿงช test ${{ matrix.py }} - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false @@ -30,47 +30,50 @@ jobs: - "3.11" os: - ubuntu-24.04 - - windows-2025 - - macos-15 + - windows-2025-vs2026 + - macos-26 exclude: - - {os: windows-2025, py: pypy3.11} + - {os: windows-2025-vs2026, py: pypy3.11} steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - - name: Install the latest version of uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 with: + version: latest-known python-version: "3.15" enable-cache: false - - name: Install tox + - name: ๐Ÿ“ฆ Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - - name: Install Python + - name: ๐Ÿ Install Python ${{ matrix.py }} run: uv python install --python-preference only-managed ${{ matrix.py }} - - name: Setup test suite + - name: ๐Ÿ“ฆ Set up test suite run: tox run -vv --notest --skip-missing-interpreters false -e ${{ matrix.py }} env: UV_PYTHON_PREFERENCE: only-managed - - name: Run test suite + - name: ๐Ÿงช Run test suite run: | - if [[ "${{ matrix.py }}" == pypy* ]]; then - tox run --skip-pkg-install -e ${{ matrix.py }} -- + if [[ "$MATRIX_PY" == pypy* ]]; then + tox run --skip-pkg-install -e "$MATRIX_PY" -- else - tox run --skip-pkg-install -e ${{ matrix.py }} + tox run --skip-pkg-install -e "$MATRIX_PY" fi shell: bash env: + MATRIX_PY: ${{ matrix.py }} PYTEST_ADDOPTS: "-vv --durations=20" UV_PYTHON_PREFERENCE: only-managed DIFF_AGAINST: HEAD - - name: Rename coverage report file + - name: ๐Ÿ“Š Rename coverage report file if: ${{ !startsWith(matrix.py, 'pypy')}} run: | import os; import sys os.rename(f".tox/.coverage.${{ matrix.py }}", f".tox/.coverage.${{ matrix.py }}-{sys.platform}") shell: python - - name: Upload coverage data + - name: ๐Ÿ“ค Upload coverage data if: ${{ !startsWith(matrix.py, 'pypy')}} uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: @@ -79,15 +82,16 @@ jobs: path: ".tox/.coverage.*" retention-days: 3 coverage: - name: Combine coverage + name: ๐Ÿ“Š Combine coverage runs-on: ubuntu-24.04 needs: test steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - - name: Download coverage data + - name: ๐Ÿ“ฉ Download coverage data id: coverage-data background: true uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 @@ -95,94 +99,76 @@ jobs: path: .tox pattern: .coverage.* merge-multiple: true - - name: Install the latest version of uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 with: + version: latest-known python-version: "3.15" enable-cache: false - - name: Install tox + - name: ๐Ÿ“ฆ Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - - name: Build package to generate version + - name: ๐Ÿ—๏ธ Build package to generate version run: uv build --python 3.15 --python-preference only-managed --wheel . --out-dir dist - - name: Setup coverage tool + - name: ๐Ÿ“ฆ Set up coverage tool run: tox -e coverage --notest env: UV_PYTHON_PREFERENCE: only-managed - - wait: coverage-data - - name: Combine and report coverage + - name: โณ Wait for coverage data + wait: coverage-data + - name: ๐Ÿ“Š Combine and report coverage run: tox -e coverage --skip-pkg-install env: UV_PYTHON_PREFERENCE: only-managed - - name: Upload HTML report + - name: ๐Ÿ“ค Upload HTML report uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: html-report path: .tox/htmlcov check: - name: ${{ matrix.tox_env }} - ${{ matrix.os }} + name: ๐Ÿ” ${{ matrix.tox_env }} - ${{ matrix.os }} runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: - ubuntu-24.04 - - windows-2025 + - windows-2025-vs2026 tox_env: - dev - type - docs - pkg_meta exclude: - - {os: windows-2025, tox_env: pkg_meta} + - {os: windows-2025-vs2026, tox_env: pkg_meta} steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - - name: Install the latest version of uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 with: + version: latest-known python-version: "3.15" enable-cache: false - - name: Install tox + - name: ๐Ÿ“ฆ Install tox run: uv tool install --python-preference only-managed --python 3.15 tox --with tox-uv - - name: Setup test suite + - name: ๐Ÿ“ฆ Set up check suite run: tox run -vv --notest --skip-missing-interpreters false -e ${{ matrix.tox_env }} env: UV_PYTHON_PREFERENCE: only-managed - - name: Run test suite + - name: ๐Ÿงช Run check for ${{ matrix.tox_env }} run: tox run --skip-pkg-install -e ${{ matrix.tox_env }} env: UV_PYTHON_PREFERENCE: only-managed - changelog: - name: ๐Ÿ“ News fragment - runs-on: ubuntu-24.04 - if: github.event_name == 'pull_request' && !contains(github.event.pull_request.labels.*.name, 'skip news') - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - name: Install the latest version of uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 - with: - python-version: "3.15" - enable-cache: false - - name: Require a news fragment - run: uvx towncrier check --compare-with "origin/${GITHUB_BASE_REF}" gate: - name: Required checks pass - if: always() - needs: [test, coverage, check, changelog] + name: ๐Ÿšฆ ${{ github.event_name == 'pull_request' && 'Required checks pass' || 'Non-PR checks pass' }} + if: ${{ !cancelled() }} # codespell:ignore cancelled + needs: [test, coverage, check] runs-on: ubuntu-24.04 steps: - - env: + - name: ๐Ÿšฆ Require all needed jobs to pass + env: NEEDS_JSON: ${{ toJSON(needs) }} - run: | - jq -e ' - all( - to_entries[]; - .value.result == "success" or - (.key == "changelog" and .value.result == "skipped") - ) - ' <<< "$NEEDS_JSON" + run: jq -e 'all(to_entries[]; .value.result == "success")' <<<"$NEEDS_JSON" diff --git a/.github/workflows/codeql.yaml b/.github/workflows/codeql.yaml new file mode 100644 index 00000000..13d9bba5 --- /dev/null +++ b/.github/workflows/codeql.yaml @@ -0,0 +1,41 @@ +name: ๐Ÿ›ก๏ธ CodeQL +on: + workflow_dispatch: + push: + branches: ["main"] + pull_request: + schedule: + - cron: "0 9 * * 2" +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true +permissions: {} +jobs: + analyze: + name: ๐Ÿ›ก๏ธ Analyze ${{ matrix.language }} + runs-on: ubuntu-26.04 + permissions: + contents: read # check out the code to analyze + security-events: write # upload the analysis results to code scanning + strategy: + fail-fast: false + matrix: + language: [actions, python] + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿ›ก๏ธ Initialize CodeQL + uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + with: + languages: ${{ matrix.language }} + build-mode: none + queries: security-extended + config: | + paths-ignore: + - tests + - name: ๐Ÿ›ก๏ธ Analyze + uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/news.yaml b/.github/workflows/news.yaml new file mode 100644 index 00000000..3960d740 --- /dev/null +++ b/.github/workflows/news.yaml @@ -0,0 +1,32 @@ +name: ๐Ÿ“ Changelog +on: + pull_request: + types: [opened, reopened, synchronize, labeled, unlabeled] +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true +permissions: + contents: read +jobs: + changelog: + name: ๐Ÿ“ News fragment + runs-on: ubuntu-26.04 + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฆ Install locked release tools + uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + groups: release-news + venv: ${{ runner.temp }}/release-tools + - name: ๐Ÿ” Validate news fragments + uses: tox-dev/github-workflows/validate-news@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 diff --git a/.github/workflows/prepare-release.yaml b/.github/workflows/prepare-release.yaml index b8dfa1d0..0eb37194 100644 --- a/.github/workflows/prepare-release.yaml +++ b/.github/workflows/prepare-release.yaml @@ -1,134 +1,22 @@ -name: ๐Ÿ› ๏ธ Prepare release +name: ๐Ÿท๏ธ Prepare release on: workflow_dispatch: inputs: bump: - description: "Version bump" + description: Version bump type required: true - default: auto type: choice options: [auto, major, minor, patch] -permissions: - contents: read + default: auto +permissions: {} jobs: - assemble: - name: ๐Ÿ“ build changelog - if: github.ref == 'refs/heads/main' - runs-on: ubuntu-24.04 - permissions: - contents: read - outputs: - version: ${{ steps.version.outputs.version }} - steps: - - name: ๐Ÿ“ฅ Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 # full history so the version calculation sees the latest tag - persist-credentials: false - - name: ๐Ÿ“ฆ Setup uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 - with: - python-version: "3.15" - enable-cache: false - - name: ๐Ÿ”ข Compute next version - id: version - env: - BUMP: ${{ inputs.bump }} - run: | - current=$(git tag --list --sort=-v:refname | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | head -1) - current=${current:-0.0.0} - IFS='.' read -r major minor patch <<< "$current" - bump="$BUMP" - if [ "$bump" = "auto" ]; then - if ls docs/changelog/*.breaking.rst >/dev/null 2>&1; then - bump=major - elif ls docs/changelog/*.feature.rst >/dev/null 2>&1; then - bump=minor - else - bump=patch - fi - fi - case "$bump" in - major) next="$((major + 1)).0.0" ;; - minor) next="$major.$((minor + 1)).0" ;; - patch) next="$major.$minor.$((patch + 1))" ;; - esac - echo "Bumping $current -> $next ($bump)" - echo "version=$next" >> "$GITHUB_OUTPUT" - - name: ๐Ÿ“ Build release patch - env: - VERSION: ${{ steps.version.outputs.version }} - run: | - set -euo pipefail - if git tag --list "$VERSION" | grep -q .; then - echo "::error::Tag $VERSION already exists" - exit 1 - fi - if ! compgen -G 'docs/changelog/*.*.rst' > /dev/null; then - echo "::error::no changelog fragments to release" - exit 1 - fi - uvx towncrier build --yes --version "$VERSION" - uvx --from pre-commit --with pre-commit-uv pre-commit run docstrfmt --files docs/changelog.rst || true - git diff HEAD --binary > "$RUNNER_TEMP/release.patch" - test -s "$RUNNER_TEMP/release.patch" - - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 - with: - name: release-patch - path: ${{ runner.temp }}/release.patch - if-no-files-found: error - push: - name: ๐Ÿ”– Commit and tag - needs: assemble - runs-on: ubuntu-24.04 - environment: release-auth + prepare: + name: ๐Ÿท๏ธ Prepare Towncrier release + uses: tox-dev/github-workflows/.github/workflows/prepare-towncrier-release.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 permissions: contents: read - steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - fetch-depth: 0 - persist-credentials: false - - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 - with: - name: release-patch - path: ${{ runner.temp }}/release-patch - - name: Validate release patch - env: - VERSION: ${{ needs.assemble.outputs.version }} - run: | - set -euo pipefail - git fetch origin main - git reset --hard origin/main - git apply --check "$RUNNER_TEMP/release-patch/release.patch" - git apply --index "$RUNNER_TEMP/release-patch/release.patch" - while IFS= read -r path; do - case "$path" in - docs/changelog.rst|docs/changelog/*.rst) ;; - *) echo "::error::unexpected release path: $path"; exit 1 ;; - esac - done < <(git diff --cached --name-only) - grep -qE "^ ${VERSION//./\\.} \(" docs/changelog.rst - git diff --cached --check - - id: token - uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0 - with: - client-id: ${{ vars.RELEASE_APP_CLIENT_ID }} - private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} - owner: ${{ github.repository_owner }} - repositories: ${{ github.event.repository.name }} - permission-contents: write - - name: Commit and tag the release - env: - VERSION: ${{ needs.assemble.outputs.version }} - GH_TOKEN: ${{ steps.token.outputs.token }} - APP_SLUG: ${{ steps.token.outputs.app-slug }} - run: | - set -euo pipefail - app_user_id=$(gh api "/users/${APP_SLUG}[bot]" --jq .id) - git config user.name "${APP_SLUG}[bot]" - git config user.email "${app_user_id}+${APP_SLUG}[bot]@users.noreply.github.com" - git commit -m "Release $VERSION" - git tag "$VERSION" - gh auth setup-git --hostname github.com --force - git push --atomic origin HEAD:main "refs/tags/$VERSION" + pull-requests: read + with: + bump: ${{ inputs.bump }} + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 2203f68d..134299fb 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml @@ -2,118 +2,157 @@ name: ๐Ÿš€ Release on: push: branches: ["main"] - tags: ["[0-9]+.[0-9]+.[0-9]+"] + tags: ["*"] pull_request: concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: release-${{ github.ref }} cancel-in-progress: ${{ !startsWith(github.ref, 'refs/tags/') }} permissions: contents: read env: dists-artifact-name: python-package-distributions jobs: - build: - name: ๐Ÿ“ฆ build - runs-on: ubuntu-24.04 + build-pr: + name: ๐Ÿ—๏ธ Build distributions + if: ${{ !startsWith(github.ref, 'refs/tags/') }} + runs-on: ubuntu-26.04 permissions: contents: read steps: - - name: ๐Ÿ“ฅ Checkout + - name: ๐Ÿ“ฅ Check out code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - fetch-depth: 0 # full history so hatch-vcs derives the version from the tag + fetch-depth: 0 persist-credentials: false - - name: ๐Ÿ“ฆ Setup uv - uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0 + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 with: + version: latest-known python-version: "3.15" - enable-cache: false # this workflow builds the artifact that gets published; no cache to poison - - name: ๐Ÿ“ฆ Build package - run: uv build --python 3.15 --python-preference only-managed --sdist --wheel . --out-dir dist - - name: ๐Ÿ“ค Store the distribution packages + enable-cache: false + - name: ๐Ÿ—๏ธ Build distributions + uses: tox-dev/github-workflows/build-python-distribution@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + - name: ๐Ÿ“ค Upload distributions uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 with: name: ${{ env.dists-artifact-name }} path: dist/* - publish: - name: ๐Ÿš€ publish - needs: [build] + if-no-files-found: error + build: + name: ๐Ÿ—๏ธ Build if: startsWith(github.ref, 'refs/tags/') - runs-on: ubuntu-24.04 + uses: tox-dev/github-workflows/.github/workflows/validate-python-release.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + permissions: + contents: read + release: + name: ๐Ÿš€ Publish to PyPI + needs: [build, notes] + runs-on: ubuntu-26.04 environment: name: release url: https://pypi.org/project/platformdirs/${{ github.ref_name }} permissions: id-token: write steps: - - name: ๐Ÿ“ฅ Checkout - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - with: - persist-credentials: false - - name: ๐Ÿ›ก๏ธ Require a changelog section for this release - env: - VERSION: ${{ github.ref_name }} - # A tag reaches PyPI only through prepare-release, which builds the changelog first. A tag pushed by hand skips - # that, so refuse to publish a version the changelog does not document rather than ship it silently. - run: | - if ! grep -qE "^ ${VERSION//./\\.} \(" docs/changelog.rst; then - echo "::error::docs/changelog.rst has no section for $VERSION; release via the Prepare release workflow" - exit 1 - fi - - name: โฌ‡๏ธ Download all the dists + - name: ๐Ÿ“ฉ Download distributions uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 with: - name: ${{ env.dists-artifact-name }} + artifact-ids: ${{ needs.build.outputs.distributions-artifact-id }} path: dist/ - name: ๐Ÿš€ Publish to PyPI uses: pypa/gh-action-pypi-publish@dc37677b2e1c63e2034f94d8a5b11f265b73ba33 # v1.14.2 with: - skip-existing: true - github-release: - needs: publish + packages-dir: dist + pypi_verify: + name: ๐Ÿ” Verify PyPI distributions + needs: [build, release] + runs-on: ubuntu-26.04 + permissions: + contents: read + steps: + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฉ Download distributions + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + artifact-ids: ${{ needs.build.outputs.distributions-artifact-id }} + path: dist + - name: ๐Ÿ” Verify PyPI artifacts + uses: tox-dev/github-workflows/reconcile-pypi-artifacts@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + project: platformdirs + version: ${{ github.ref_name }} + dist: dist + notes: + name: ๐Ÿ“ Render GitHub Release notes if: startsWith(github.ref, 'refs/tags/') - runs-on: ubuntu-24.04 + runs-on: ubuntu-26.04 permissions: - contents: write + contents: read + outputs: + artifact-id: ${{ steps.upload.outputs.artifact-id }} steps: - - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: ๐Ÿ“ฅ Check out code + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 persist-credentials: false - - name: ๐Ÿ“ข Create GitHub release + - name: ๐Ÿ Install uv + uses: astral-sh/setup-uv@07a047e608db84b3d8c06cd9a7c7dcc9c355c18e # v10.3.2 + with: + version: latest-known + python-version: "3.15" + enable-cache: false + - name: ๐Ÿ“ฆ Install locked release tools + uses: tox-dev/github-workflows/install-locked-tools@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + groups: release-notes + venv: ${{ runner.temp }}/release-tools + - name: ๐Ÿท๏ธ Select previous tag + id: previous + uses: tox-dev/github-workflows/select-previous-tag@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + tag: ${{ github.ref_name }} + - name: ๐Ÿ“ Render release notes + uses: tox-dev/github-workflows/render-release-notes@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + with: + tag: ${{ github.ref_name }} + previous: ${{ steps.previous.outputs.previous }} + changelog: docs/changelog.rst + artifact-url: https://pypi.org/project/platformdirs/${{ github.ref_name }}/ + - name: ๐Ÿ“ค Upload release notes + id: upload + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: github-release-notes + path: ${{ runner.temp }}/release-notes.md + if-no-files-found: error + github-release: + name: ๐Ÿš€ Publish GitHub Release + needs: [pypi_verify, notes] + runs-on: ubuntu-26.04 + permissions: + contents: write + steps: + - name: ๐Ÿ“ฉ Download release notes + uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2 + with: + artifact-ids: ${{ needs.notes.outputs.artifact-id }} + path: ${{ runner.temp }}/release-notes + - name: ๐Ÿš€ Publish GitHub release + uses: tox-dev/github-workflows/publish-github-release@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 env: GH_TOKEN: ${{ github.token }} - VERSION: ${{ github.ref_name }} - run: | - set -euo pipefail - awk -v version="$VERSION" ' - index($0, " " version " (") == 1 { found = 1; next } - found && /^ [0-9]+\.[0-9]+\.[0-9]+ \(/ { exit } - found && $0 !~ /^\*+$/ { print } - ' docs/changelog.rst > "$RUNNER_TEMP/release-notes.md" - python3 - "$RUNNER_TEMP/release-notes.md" <<'PY' - import re - import sys - from pathlib import Path - - path = Path(sys.argv[1]) - body = path.read_text().strip() - body = re.sub(r":user:`([^`]+)`", r"\1", body) - body = re.sub(r":(?:pr|issue):`(\d+)`", r"#\1", body) - body = re.sub(r":[a-z]+:`~?([^`]+)`", lambda match: f"`{match.group(1).split('.')[-1]}`", body) - if not body: - raise SystemExit("release notes are empty") - path.write_text(body.replace("``", "`") + "\n") - PY - printf '\n[PyPI release](https://pypi.org/project/platformdirs/%s/)\n' "$VERSION" >> "$RUNNER_TEMP/release-notes.md" - previous=$({ gh api "repos/$GITHUB_REPOSITORY/releases?per_page=100" --paginate --jq '.[].tag_name'; printf '%s\n' "$VERSION"; } | grep -E '^[0-9]+\.[0-9]+\.[0-9]+$' | sort -Vu | awk -v tag="$VERSION" '$0 == tag { print previous; exit } { previous = $0 }') - if [[ -n "$previous" ]]; then - printf '\n**Full Changelog**: https://github.com/%s/compare/%s...%s\n' "$GITHUB_REPOSITORY" "$previous" "$VERSION" >> "$RUNNER_TEMP/release-notes.md" - else - printf '\n**Full Changelog**: https://github.com/%s/commits/%s\n' "$GITHUB_REPOSITORY" "$VERSION" >> "$RUNNER_TEMP/release-notes.md" - fi - if gh release view "$VERSION" --repo "$GITHUB_REPOSITORY" > /dev/null 2>&1; then - gh release edit "$VERSION" --repo "$GITHUB_REPOSITORY" --notes-file "$RUNNER_TEMP/release-notes.md" - else - gh release create "$VERSION" --repo "$GITHUB_REPOSITORY" --title="$VERSION" --verify-tag --notes-file "$RUNNER_TEMP/release-notes.md" - fi + with: + tag: ${{ github.ref_name }} + commit: ${{ github.sha }} + title: ${{ github.ref_name }} + notes-file: ${{ runner.temp }}/release-notes/release-notes.md diff --git a/.github/workflows/upgrade-release-tools.yaml b/.github/workflows/upgrade-release-tools.yaml new file mode 100644 index 00000000..38eadd5e --- /dev/null +++ b/.github/workflows/upgrade-release-tools.yaml @@ -0,0 +1,22 @@ +name: ๐Ÿ”’ Upgrade release tools +on: + workflow_dispatch: + schedule: + - cron: "0 8 * * 2" +permissions: {} +concurrency: + group: upgrade-release-tools + cancel-in-progress: false +jobs: + upgrade: + name: ๐Ÿ”€ Upgrade release tools + uses: tox-dev/github-workflows/.github/workflows/upgrade-release-tools.yaml@259a3d3fb578d00517ffb73341fdd463259b0b2f # 6.0.1 + permissions: + contents: read + secrets: + RELEASE_APP_PRIVATE_KEY: ${{ secrets.RELEASE_APP_PRIVATE_KEY }} + with: + commit-message: "build(deps): refresh project lock" + pull-request-title: "build(deps): refresh project lock" + pull-request-body: |- + Relock `pylock.toml` with every dependency group upgraded to releases past the seven-day cooldown. diff --git a/.gitignore b/.gitignore index 4683247f..5ba44614 100644 --- a/.gitignore +++ b/.gitignore @@ -7,3 +7,4 @@ /docs/build /.coverage /.coverage.* +/uv.lock diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index c5fa70ae..acaced6e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,56 +1,60 @@ +ci: + autoupdate_schedule: quarterly default_language_version: python: python3 repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v6.0.0 + rev: 3e8a8703264a2f4a69428a0aa4dcb512790b2c8c # frozen: v6.0.0 hooks: - id: end-of-file-fixer - id: trailing-whitespace - repo: https://github.com/python-jsonschema/check-jsonschema - rev: 0.38.2 + rev: 0494aa7fa1314e98913a41227d8f0a515b2c1049 # frozen: 0.38.2 hooks: - id: check-github-workflows args: ["--verbose"] - repo: https://github.com/codespell-project/codespell - rev: v2.4.3 + rev: 57b21406f092110c18776e39b0bda50d37c945c8 # frozen: v2.4.3 hooks: - id: codespell - repo: https://github.com/tox-dev/tox-toml-fmt - rev: "v1.11.1" + rev: "5125f601c3e134347288c3d42f3b34298b7cf1be" # frozen: v1.11.1 hooks: - id: tox-toml-fmt - repo: https://github.com/tox-dev/pyproject-fmt - rev: "v2.30.3" + rev: "50e0f3aee9dc5747a5f173f79a7417403c18dda6" # frozen: v2.30.3 hooks: - id: pyproject-fmt - repo: https://github.com/astral-sh/ruff-pre-commit - rev: "v0.17.1" + rev: "38bfb07c0c64c304f47eb52090f8288150c77730" # frozen: v0.17.1 hooks: - id: ruff-format - id: ruff-check args: ["--fix", "--unsafe-fixes", "--exit-non-zero-on-fix"] - repo: https://github.com/google/yamlfmt - rev: "v0.21.0" + rev: "21ca5323a9c87ee37a434e0ca908efc0a89daa07" # frozen: v0.21.0 hooks: - id: yamlfmt - - repo: local + - repo: https://github.com/hukkin/mdformat + rev: 82912cdaea4fb830f751504486a7879c70526547 # frozen: 1.0.0 hooks: - id: mdformat - name: mdformat - entry: mdformat --wrap 120 - language: python - types: [markdown] + args: ["--wrap", "120"] additional_dependencies: - - mdformat-gfm>=1 - - mdformat-ruff>=0.1.3 + - mdformat-gfm==1.0.0 + - mdformat-ruff==0.1.3 - repo: https://github.com/LilSpazJoekp/docstrfmt - rev: v2.2.1 + rev: c1813841673cdcd6cf602dde1edb78a5d5e45235 # frozen: v2.2.1 hooks: - id: docstrfmt - args: ["-l", "120"] - additional_dependencies: ["sphinx>=9.1"] + files: | + (?x) + ^(?Pdocs/changelog[.]rst)$ # Only the generated release history. + args: ["-l", "120", "--preserve-adornments"] + additional_dependencies: + - "sphinx==9.1.0" - repo: https://github.com/zizmorcore/zizmor-pre-commit - rev: v1.31.1 + rev: c92afdf2c6ca336aaa8f39e2bd8d48f62dbd8e1f # frozen: v1.31.1 hooks: - id: zizmor - repo: meta diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b6b53d27..52e95b52 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,6 +86,34 @@ target 100% code coverage. When making user-facing changes, update relevant `.rst` files in `docs/`. Add docstrings to new public functions. Update examples if behavior changes. Run `tox r -e docs` to verify documentation builds. +### Changelog entries + +Add one `.rst` file under `docs/changelog/` for each user-facing change. Named fragments need a `+` prefix and a +category suffix, such as `+linux-runtime.bugfix.rst` or `+python-315.feature.rst`. Write only the change in the +fragment: + +```rst +Skip an XDG runtime directory owned by another user. +``` + +Leave out the PR number and any credit; the news check rejects hand-written ones. When a release is prepared, the +release tooling links the fragment to its squash-merged PR and credits the authors of the merge commit, the PR author +first and then every other commit author and co-author, in a single byline: + +```rst +- Skip an XDG runtime directory owned by another user. :pr:`42` - by :user:`alice` and :user:`bob`. +``` + +AI assistant identities are dropped, and bots are credited only when they are the only author. Release preparation also +runs `release-creator contributors`, which adds a "New Contributors" subsection to the new changelog section. GitHub +Release notes use `@alice and @bob` instead of Sphinx roles. + +Use `feature` for added capabilities and Python support changes, `change` for changed behavior, `bugfix` for fixes, and +`doc` for documentation that affects users. Use `security`, `performance`, `deprecation`, `removal`, `breaking`, or +`packaging` when that distinction matters to users. Keep maintenance-only work out of the changelog. If a PR needs no +entry, apply the `skip news` label; it can be added after opening the PR. Bot PRs get this label automatically unless +they include a fragment. + ## Submitting Changes ### Commit Messages diff --git a/docs/changelog.rst b/docs/changelog.rst index a772959a..6ff9b9d3 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -6,703 +6,1418 @@ .. towncrier release notes start +.. _release-4-13-5: + ********************* 4.13.5 (2026-10-19) ********************* +.. _release-4-13-5-packaging: + +Packaging +========= + - Publish a GitHub Release with changelog notes, a PyPI link, and a version comparison after each PyPI release. - :pr:`631` + :pr:`631` - by :user:`gaborbernat`. + +.. _release-4-13-4: ********************* 4.13.4 (2026-10-17) ********************* -- Require a complete ``files`` path segment when locating Android app directories from ``sys.path``. :pr:`621` -- Keep root directory tests independent of inherited XDG environment variables. :pr:`622` +.. _release-4-13-4-fixed: + +Fixed +===== + +- Require a complete ``files`` path segment when locating Android app directories from ``sys.path``. :pr:`621` - by + :user:`shoaibulhaque` and :user:`gaborbernat`. - Raise ``RuntimeError`` when iOS cannot resolve the home directory, rather than returning paths rooted at a literal - ``~``. :pr:`624` + ``~``. :pr:`624` - by :user:`XXXXXQ-0206` and :user:`gaborbernat`. - Keep user directory strings, paths and iterators consistent inside ``isolated_dirs`` when Unix root enables - ``use_site_for_root``. Restore root redirection when the context exits. :pr:`625` + ``use_site_for_root``. Restore root redirection when the context exits. :pr:`625` - by :user:`AryanRG` and + :user:`gaborbernat`. - Raise ``RuntimeError`` when the Windows Projects directory cannot resolve the home directory, rather than returning a - path rooted at a literal ``~``. :pr:`627` -- Correct the contributor guide to name ty as the type checker used by the type environment. :pr:`623` + path rooted at a literal ``~``. :pr:`627` - by :user:`XXXXXQ-0206`. + +.. _release-4-13-3: ********************* 4.13.3 (2026-10-16) ********************* +.. _release-4-13-2: + ********************* 4.13.2 (2026-10-16) ********************* -- Normalize ``user_fonts_dir`` when ``XDG_DATA_HOME`` ends with a separator. :pr:`619` +.. _release-4-13-2-fixed: + +Fixed +===== + +- Normalize ``user_fonts_dir`` when ``XDG_DATA_HOME`` ends with a separator. :pr:`619` - by :user:`blouirts123` and + :user:`gaborbernat`. + +.. _release-4-13-1: ********************* 4.13.1 (2026-10-15) ********************* -- Free the path buffer from ``SHGetKnownFolderPath`` when the known-folder lookup fails. :pr:`618` +.. _release-4-13-1-fixed: + +Fixed +===== + - Preserve literal backslashes before ordinary characters in double-quoted ``user-dirs.dirs`` paths instead of removing - them. + them. :pr:`614` - by :user:`xiehuanyi` and :user:`gaborbernat`. +- Avoid leaking the Windows known-folder path buffer when a lookup fails. :pr:`618` - by :user:`gaborbernat` and + :user:`repzakske`. + +.. _release-4-13-0: ********************* 4.13.0 (2026-10-10) ********************* +.. _release-4-13-0-fixed: + +Fixed +===== + - Detect Homebrew Python for the :class:`~platformdirs.macos.MacOS` site directories under :option:`python:-S`, which - leaves :data:`sys.base_prefix` on the ``Cellar`` keg, and for the ``python-freethreading`` formula - by - :user:`sricharanreddycheruku`. :pr:`612` -- Use Python 3.15 for development and automation. :pr:`613` + leaves :data:`sys.base_prefix` on the ``Cellar`` keg, and for the ``python-freethreading`` formula. :pr:`612` - by + :user:`sricharanreddycheruku` and :user:`gaborbernat`. + +.. _release-4-12-4: ********************* 4.12.4 (2026-10-07) ********************* +.. _release-4-12-4-fixed: + +Fixed +===== + - Keep site directories readable by other users when root calls :meth:`~platformdirs.api.PlatformDirsABC.place_config_file` or another ``place_*_file`` method with - :attr:`~platformdirs.api.PlatformDirsABC.use_site_for_root` - by :user:`darrenhuai`. :pr:`610` + :attr:`~platformdirs.api.PlatformDirsABC.use_site_for_root`. :pr:`610` - by :user:`darrenhuai` and + :user:`gaborbernat`. - Make :func:`~platformdirs.user_runtime_dir` warn and fall back from an unreachable ``XDG_RUNTIME_DIR`` under - :attr:`~platformdirs.api.PlatformDirsABC.ensure_exists` instead of raising. :pr:`611` + :attr:`~platformdirs.api.PlatformDirsABC.ensure_exists` instead of raising. :pr:`611` - by :user:`harbinresearcher` + and :user:`gaborbernat`. + +.. _release-4-12-3: ********************* 4.12.3 (2026-10-03) ********************* +.. _release-4-12-3-fixed: + +Fixed +===== + - Place files from ``place_config_file`` and ``place_data_file`` in the first site directory for root on Unix with ``use_site_for_root=True`` and ``multipath=True``, where ``find_config_file`` and ``find_data_file`` look for them. - :pr:`607` + :pr:`607` - by :user:`PDGGK` and :user:`gaborbernat`. + +.. _release-4-12-2: ********************* 4.12.2 (2026-09-29) ********************* +.. _release-4-12-2-fixed: + +Fixed +===== + - Keep ``os.pathsep`` in ``site_applications_path`` under ``multipath=True`` on platforms with one applications - directory. :pr:`604` + directory. :pr:`604` - by :user:`9Kun` and :user:`gaborbernat`. + +.. _release-4-12-1: ********************* 4.12.1 (2026-09-28) ********************* -- Avoid ``PytestAssertRewriteWarning`` when importing ``platformdirs`` before invoking pytest. :pr:`601` +.. _release-4-12-1-fixed: + +Fixed +===== + +- Avoid ``PytestAssertRewriteWarning`` when importing ``platformdirs`` before invoking pytest. :issue:`601` :pr:`602` - + by :user:`gaborbernat`. + +.. _release-4-12-0: ********************* 4.12.0 (2026-09-26) ********************* +.. _release-4-12-0-added: + +Added +===== + - Add ``place_*_file`` methods that return a file path under a user directory and create its missing parents with mode - ``0o700``. :pr:`585` + ``0o700``. :pr:`585` - by :user:`gaborbernat`. - Add ``find__file`` and ``find__files`` to look up an existing file across the user and site directories of - each kind that has an ``iter__paths`` method. :pr:`586` + each kind that has an ``iter__paths`` method. :pr:`586` - by :user:`gaborbernat`. - Add :func:`platformdirs.testing.isolated_dirs` and the ``platformdirs_isolated`` pytest fixture to resolve every - directory under one test root. :pr:`590` + directory under one test root. :pr:`590` - by :user:`gaborbernat`. - Emit :class:`~platformdirs.RuntimeDirWarning` when the Unix :func:`~platformdirs.user_runtime_dir` falls back from - ``XDG_RUNTIME_DIR``. :pr:`599` + ``XDG_RUNTIME_DIR``. :pr:`599` - by :user:`gaborbernat`. - Read ``user_templates_dir``, ``user_publicshare_dir`` and ``user_bin_dir`` on Windows from their known folders. - :pr:`587` -- Create missing user app directories and their parents with mode ``0700`` under ``ensure_exists`` on POSIX platforms. - :pr:`588` + :pr:`587` - by :user:`gaborbernat`. +- Use the app container layout on iOS, such as ``~/Library/Application Support`` for data. :pr:`600` - by + :user:`gaborbernat`. + +.. _release-4-12-0-fixed: + +Fixed +===== + - Raise ``RuntimeError`` for a Unix or macOS directory under the home when no home resolves, and read the password - database for an empty ``HOME``. :pr:`589` -- Skip an ``XDG_RUNTIME_DIR`` or ``/run/user/`` that is not a private directory of the user, and reject a symlink - or file as the ``runtime-`` fallback. :pr:`599` -- Use the app container layout on iOS, such as ``~/Library/Application Support`` for data. :pr:`600` + database for an empty ``HOME``. :pr:`589` - by :user:`gaborbernat`. + +.. _release-4-12-0-documentation: + +Documentation +============= + - Document that a Homebrew Python puts the Homebrew prefix first in the macOS shared directories, with or without - ``multipath``. :pr:`591` -- Document that the macOS media directories honor the ``XDG_*_DIR`` variables. :pr:`592` -- Document the ``WIN_PD_OVERRIDE_COMMON_PROGRAMS`` variable. :pr:`593` -- Document ``/usr/local/share/applications`` as the Linux ``site_applications_dir`` default. :pr:`594` -- Correct the BSD ``user_runtime_dir`` defaults and describe the temporary directory fallback. :pr:`595` -- Describe how platformdirs detects Android, finds the app folder and places the shared folders. :pr:`596` -- Document that Microsoft Store Python redirects only new files and folders under ``AppData``. :pr:`597` -- Show how to load a font on Windows after copying it into ``user_fonts_dir``. :pr:`598` + ``multipath``. :pr:`591` - by :user:`gaborbernat`. +- Document that the macOS media directories honor the ``XDG_*_DIR`` variables. :pr:`592` - by :user:`gaborbernat`. +- Document the ``WIN_PD_OVERRIDE_COMMON_PROGRAMS`` variable. :pr:`593` - by :user:`gaborbernat`. +- Document ``/usr/local/share/applications`` as the Linux ``site_applications_dir`` default. :pr:`594` - by + :user:`gaborbernat`. +- Correct the BSD ``user_runtime_dir`` defaults and describe the temporary directory fallback. :pr:`595` - by + :user:`gaborbernat`. +- Describe how platformdirs detects Android, finds the app folder and places the shared folders. :pr:`596` - by + :user:`gaborbernat`. +- Document that Microsoft Store Python redirects only new files and folders under ``AppData``. :pr:`597` - by + :user:`gaborbernat`. +- Show how to load a font on Windows after copying it into ``user_fonts_dir``. :pr:`598` - by :user:`gaborbernat`. + +.. _release-4-12-0-security: + +Security +======== + +- Create missing user app directories and their parents with mode ``0700`` under ``ensure_exists`` on POSIX platforms. + :pr:`588` - by :user:`gaborbernat`. +- Skip an ``XDG_RUNTIME_DIR`` or ``/run/user/`` that is not a private directory of the user, and reject a symlink + or file as the ``runtime-`` fallback. :pr:`599` - by :user:`gaborbernat`. + +.. _release-4-11-15: ********************** 4.11.15 (2026-09-26) ********************** -- Fix the pyjnius lookup of the Android app folder and media directories, which always failed. :pr:`580` -- Detect Android from ``sys.getandroidapilevel`` when ``ANDROID_DATA`` and ``ANDROID_ROOT`` are unset. :pr:`581` -- Put Android shared-storage directories under the current user's /storage/emulated/, not user 0's. :pr:`582` +.. _release-4-11-15-fixed: + +Fixed +===== + +- Fix the pyjnius lookup of the Android app folder and media directories, which always failed. :pr:`580` - by + :user:`gaborbernat`. +- Detect Android from ``sys.getandroidapilevel`` when ``ANDROID_DATA`` and ``ANDROID_ROOT`` are unset. :pr:`581` - by + :user:`gaborbernat`. +- Put Android shared-storage directories under the current user's /storage/emulated/, not user 0's. :pr:`582` - + by :user:`gaborbernat`. - Move Android videos to ``Movies`` and the five non-standard media folders, such as ``Desktop``, into ``Documents``. - :pr:`583` + :pr:`583` - by :user:`gaborbernat`. + +.. _release-4-11-14: ********************** 4.11.14 (2026-09-25) ********************** +.. _release-4-11-14-added: + +Added +===== + +- Accept ``roaming`` in :func:`~platformdirs.user_log_dir` and :func:`~platformdirs.user_log_path`. :pr:`572` - by + :user:`gaborbernat`. + +.. _release-4-11-14-fixed: + +Fixed +===== + - With ``ensure_exists``, create a media directory such as ``user_documents_dir`` only when the user set it through an ``XDG_*_DIR`` variable or ``user-dirs.dirs``, and return a dangling symlink there instead of raising ``FileExistsError``. 4.11.13 also created the platform defaults, which filled headless home directories with folders - such as ``~/Templates`` and made a literal ``~`` directory when ``HOME`` was unset. :pr:`561` -- Ignore ``$XDG_RUNTIME_DIR`` in ``user_runtime_dir`` when ``use_site_for_root`` redirects root. :pr:`562` + such as ``~/Templates`` and made a literal ``~`` directory when ``HOME`` was unset. :pr:`561` - by + :user:`gaborbernat`. +- Ignore ``$XDG_RUNTIME_DIR`` in ``user_runtime_dir`` when ``use_site_for_root`` redirects root. :pr:`562` - by + :user:`gaborbernat`. - Return ``/storage/emulated/0/Download`` from the Android :func:`~platformdirs.user_downloads_dir` fallback. :pr:`563` -- Ignore ``WIN_PD_OVERRIDE_*`` values that lack a drive or a root. :pr:`564` -- Find the Android app folder for package names that start with ``files``. :pr:`565` -- Reject an ``appname``, ``appauthor`` or ``version`` that leaves the base directory when set after construction. - :pr:`566` -- Apply a changed ``use_site_for_root`` on the next read. :pr:`567` -- Stop raising ``UnicodeDecodeError`` on ``user-dirs.dirs`` bytes the locale encoding cannot decode. :pr:`568` -- Drop a trailing ``# comment`` from unquoted ``user-dirs.dirs`` values. :pr:`569` -- Treat empty Windows folder variables, such as ``PUBLIC`` or ``LOCALAPPDATA``, as unset. :pr:`571` -- Accept ``roaming`` in :func:`~platformdirs.user_log_dir` and :func:`~platformdirs.user_log_path`. :pr:`572` -- Detect Homebrew Python on macOS by its ``opt/python*/Frameworks`` layout. :pr:`573` -- Keep colons in the Unix ``site_cache_path`` under ``multipath``. :pr:`574` -- Return long Windows folder paths in place of 8.3 short names. :pr:`575` -- Create the Unix ``runtime-`` temporary fallback with mode ``0700`` and reject one another user owns. :pr:`576` + - by :user:`gaborbernat`. +- Ignore ``WIN_PD_OVERRIDE_*`` values that lack a drive or a root. :pr:`564` - by :user:`gaborbernat`. +- Find the Android app folder for package names that start with ``files``. :pr:`565` - by :user:`gaborbernat`. +- Apply a changed ``use_site_for_root`` on the next read. :pr:`567` - by :user:`gaborbernat`. +- Stop raising ``UnicodeDecodeError`` on ``user-dirs.dirs`` bytes the locale encoding cannot decode. :pr:`568` - by + :user:`gaborbernat`. +- Drop a trailing ``# comment`` from unquoted ``user-dirs.dirs`` values. :pr:`569` - by :user:`gaborbernat`. +- Treat empty Windows folder variables, such as ``PUBLIC`` or ``LOCALAPPDATA``, as unset. :pr:`571` - by + :user:`gaborbernat`. +- Detect Homebrew Python on macOS by its ``opt/python*/Frameworks`` layout. :pr:`573` - by :user:`gaborbernat`. +- Keep colons in the Unix ``site_cache_path`` under ``multipath``. :pr:`574` - by :user:`gaborbernat`. +- Return long Windows folder paths in place of 8.3 short names. :pr:`575` - by :user:`gaborbernat`. - Raise ``RuntimeError`` in place of creating a literal ``~`` directory when ``ensure_exists`` finds no home. :pr:`578` -- Fix the Windows ``user_preference_dir`` path in the platform docs. :pr:`577` -- Document that the macOS ``user_state_dir`` and ``site_state_dir`` ignore the ``XDG_DATA_*`` variables. :pr:`579` + - by :user:`gaborbernat`. + +.. _release-4-11-14-documentation: + +Documentation +============= + +- Fix the Windows ``user_preference_dir`` path in the platform docs. :pr:`577` - by :user:`gaborbernat`. +- Document that the macOS ``user_state_dir`` and ``site_state_dir`` ignore the ``XDG_DATA_*`` variables. :pr:`579` - by + :user:`gaborbernat`. + +.. _release-4-11-14-security: + +Security +======== + +- Reject an ``appname``, ``appauthor`` or ``version`` that leaves the base directory when set after construction. + :pr:`566` - by :user:`gaborbernat`. +- Create the Unix ``runtime-`` temporary fallback with mode ``0700`` and reject one another user owns. :pr:`576` - + by :user:`gaborbernat`. + +.. _release-4-11-13: ********************** 4.11.13 (2026-09-25) ********************** +.. _release-4-11-13-fixed: + +Fixed +===== + - With ``ensure_exists``, the media directories such as ``user_documents_dir`` are created on Unix, and on macOS when an - XDG variable sets them - by :user:`ekanshul`. :pr:`560` + XDG variable sets them. :pr:`560` - by :user:`gaborbernat` and :user:`ekanshul`. + +.. _release-4-11-12: ********************** 4.11.12 (2026-09-22) ********************** +.. _release-4-11-12-fixed: + +Fixed +===== + - Ignore relative paths in the XDG user directory environment variables, so ``XDG_DOCUMENTS_DIR=Documents`` no longer makes :func:`~platformdirs.user_documents_dir` and the other media directories return a path relative to the working directory. They now fall back to the platform default like the XDG Base Directory variables, and like the same keys - read from ``user-dirs.dirs`` - by :user:`darrenhuai`. :pr:`554` -- Copy nested directories in the versioned data migration recipe. :pr:`553` -- Exclude sphinx-llm 1.1.0 from documentation dependencies because its Markdown builder emits unknown-node warnings. - :pr:`556` + read from ``user-dirs.dirs``. :pr:`554` - by :user:`darrenhuai`. + +.. _release-4-11-12-documentation: + +Documentation +============= + +- Copy nested directories in the versioned data migration recipe. :pr:`553` - by :user:`agammann`. + +.. _release-4-11-11: ********************** 4.11.11 (2026-09-19) ********************** +.. _release-4-11-11-security: + +Security +======== + - Reject ``appname``, ``appauthor`` and ``version`` values that leave the platform base directory (a ``..`` segment, a leading separator, a drive or a UNC share) with ``ValueError``, so ``ensure_exists`` cannot create directories outside - it - by :user:`Pitchfork-and-Torch`. :pr:`552` + it. :pr:`552` - by :user:`Pitchfork-and-Torch` and :user:`gaborbernat`. + +.. _release-4-11-10: ********************** 4.11.10 (2026-09-18) ********************** +.. _release-4-11-10-fixed: + +Fixed +===== + - With ``ensure_exists``, the ``site_*_dir`` and ``site_*_path`` properties and the ``iter_*_dirs`` iterators only - create the site directories they return or yield, instead of every entry in the site list - by :user:`darrenhuai`. - :pr:`550` + create the site directories they return or yield, instead of every entry in the site list. :pr:`550` - by + :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-9: ********************* 4.11.9 (2026-09-16) ********************* +.. _release-4-11-9-added: + +Added +===== + - Accept ``multipath`` in :func:`~platformdirs.site_cache_dir` and :func:`~platformdirs.site_cache_path`. Without it, the function API could not return the Homebrew cache prefix that :attr:`~platformdirs.macos.MacOS.site_cache_dir` adds - under ``multipath`` - by :user:`darrenhuai`. :pr:`544` + under ``multipath``. :pr:`544` - by :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-9-fixed: + +Fixed +===== + - Parse Unix ``user-dirs.dirs`` line by line like ``xdg-user-dir``. The INI parser raised on a repeated key or a line without ``=``, and returned trailing comments and backslash escapes inside :func:`~platformdirs.user_documents_dir` and the other media directories. The last valid assignment now wins, and platformdirs unescapes the quoted value and - ignores text after the closing quote - by :user:`darrenhuai`. :pr:`545` + ignores text after the closing quote. :pr:`545` - by :user:`darrenhuai` and :user:`gaborbernat`. - Read ``PUBLIC`` before the home directory in :func:`~platformdirs.user_publicshare_dir` on Windows, so it no longer - raises ``RuntimeError`` when ``PUBLIC`` is set and the home directory cannot be determined - by :user:`emme1t`. - :pr:`546` + raises ``RuntimeError`` when ``PUBLIC`` is set and the home directory cannot be determined. :pr:`546` - by + :user:`emme1t` and :user:`gaborbernat`. - Raise ``RuntimeError`` from :class:`~platformdirs.android.Android` directories when the app folder cannot be found, - instead of ``TypeError: expected str, bytes or os.PathLike object, not NoneType`` - by :user:`Str0k`. :pr:`547` + instead of ``TypeError: expected str, bytes or os.PathLike object, not NoneType``. :pr:`547` - by :user:`Str0k` and + :user:`gaborbernat`. + +.. _release-4-11-8: ********************* 4.11.8 (2026-09-08) ********************* +.. _release-4-11-8-fixed: + +Fixed +===== + - Make :func:`~platformdirs.user_data_path`, :func:`~platformdirs.user_config_path`, :func:`~platformdirs.user_preference_path` and :func:`~platformdirs.user_applications_path` return the first site entry when root is redirected by ``use_site_for_root`` under ``multipath``, matching their ``site_*_path`` twins. They - passed the whole joined list to :class:`~pathlib.Path`, giving one unusable path such as ``/xdg/a/foo:/xdg/b/foo`` - - by :user:`darrenhuai`. :pr:`538` + passed the whole joined list to :class:`~pathlib.Path`, giving one unusable path such as ``/xdg/a/foo:/xdg/b/foo``. + :pr:`538` - by :user:`darrenhuai` and :user:`gaborbernat`. - Ignore relative paths in XDG Base Directory environment variables and use the existing platform fallback. Relative - entries in ``$XDG_DATA_DIRS`` and ``$XDG_CONFIG_DIRS`` are skipped. :pr:`540` + entries in ``$XDG_DATA_DIRS`` and ``$XDG_CONFIG_DIRS`` are skipped. :pr:`540` - by :user:`lakshayxi` and + :user:`gaborbernat`. - Preserve literal percent signs in Unix ``user-dirs.dirs`` paths, including ``100% complete``, ``100%%`` and - ``%(XDG_DESKTOP_DIR)s``. Continue to expand ``$HOME``. :pr:`542` + ``%(XDG_DESKTOP_DIR)s``. Continue to expand ``$HOME``. :pr:`542` - by :user:`jackwalkerlabs` and :user:`gaborbernat`. - Use the base Python installation to locate Homebrew site directories on macOS, preserving shared data, config, cache - and state paths inside virtual environments. :pr:`543` + and state paths inside virtual environments. :pr:`543` - by :user:`jackwalkerlabs` and :user:`gaborbernat`. + +.. _release-4-11-7: ********************* 4.11.7 (2026-09-01) ********************* +.. _release-4-11-6: + ********************* 4.11.6 (2026-09-01) ********************* +.. _release-4-11-6-added: + +Added +===== + - Give :func:`~platformdirs.user_bin_dir` and :func:`~platformdirs.user_bin_path` the ``use_site_for_root`` argument. - They took none, so neither could reach the Unix redirect of root to :func:`~platformdirs.site_bin_dir`. :pr:`537` + They took none, so neither could reach the Unix redirect of root to :func:`~platformdirs.site_bin_dir`. :pr:`537` - by + :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-5: ********************* 4.11.5 (2026-08-27) ********************* +.. _release-4-11-5-added: + +Added +===== + - Give :func:`~platformdirs.user_preference_dir` and :func:`~platformdirs.user_preference_path` the same arguments as - :func:`~platformdirs.user_config_dir`. Added without arguments in :pr:`491`, they could only return the unscoped base - directory even though the property they wrap appends the app name and version. :pr:`531` -- Make :func:`~platformdirs.site_applications_path` return the first entry when ``multipath=True``, matching - :func:`~platformdirs.site_data_path`. On Unix and macOS it passed the whole ``$XDG_DATA_DIRS`` list to - :class:`~pathlib.Path`, giving one unusable path such as ``/first/applications:/second/applications``. :pr:`532` + :func:`~platformdirs.user_config_dir`. The functions were introduced in 4.10.0 without arguments, so they could only + return the unscoped base directory even though the property they wrap appends the app name and version. :pr:`491` + :pr:`531` - by :user:`gaborbernat` and :user:`dylanpulver`. - Give :func:`~platformdirs.user_applications_dir`, :func:`~platformdirs.user_applications_path`, :func:`~platformdirs.site_applications_dir` and :func:`~platformdirs.site_applications_path` the app arguments. Android scopes both applications directories to the app, so without them the functions could only return the unscoped base directory there. On the two site functions they are keyword-only, keeping ``multipath`` first positional as it - has been since 4.9.0; the two user functions take their boolean options keyword-only. :pr:`534` + has been since 4.9.0; the two user functions take their boolean options keyword-only. :pr:`534` - by + :user:`gaborbernat`. + +.. _release-4-11-5-fixed: + +Fixed +===== + +- Make :func:`~platformdirs.site_applications_path` return the first entry when ``multipath=True``, matching + :func:`~platformdirs.site_data_path`. On Unix and macOS it passed the whole ``$XDG_DATA_DIRS`` list to + :class:`~pathlib.Path`, giving one unusable path such as ``/first/applications:/second/applications``. :pr:`532` - by + :user:`tunglambk` and :user:`gaborbernat`. + +.. _release-4-11-5-documentation: + +Documentation +============= + - Correct the ordering note on the iterator methods. ``use_site_for_root`` drops the user directory entirely, so the iterators are documented as yielding the most specific directory first rather than always yielding the user one. - :pr:`533` + :pr:`533` - by :user:`gaborbernat`. + +.. _release-4-11-4: ********************* 4.11.4 (2026-08-24) ********************* +.. _release-4-11-4-fixed: + +Fixed +===== + - Stop the ``iter_*_dirs`` methods yielding the same directory twice when a site directory resolves to its user - equivalent - :pr:`520` covered only Unix with ``use_site_for_root``. It also hit + equivalent - covered only Unix with ``use_site_for_root``. It also hit :meth:`~platformdirs.PlatformDirs.iter_runtime_dirs` on Unix with ``$XDG_RUNTIME_DIR`` set, on Windows and macOS, and - all six iterators on Android. :pr:`524` + all six iterators on Android. :pr:`520` :pr:`524` - by :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-4-documentation: + +Documentation +============= + - Fix the config merging example in the how-to guide. ``iter_config_paths`` yields the user directory first, so the - ``config.update`` loop let the site defaults override the user's config instead of the other way round. :pr:`529` + ``config.update`` loop let the site defaults override the user's config instead of the other way round. :pr:`529` - by + :user:`gaborbernat`. + +.. _release-4-11-3: ********************* 4.11.3 (2026-08-13) ********************* +.. _release-4-11-3-added: + +Added +===== + - ``python -m platformdirs`` now lists :func:`~platformdirs.user_desktop_dir`, which was missing from the properties it - prints. :pr:`523` + prints. :pr:`523` - by :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-3-fixed: + +Fixed +===== + - Stop :func:`~platformdirs.site_data_dir`, :func:`~platformdirs.site_config_dir` and :func:`~platformdirs.site_applications_dir` raising ``IndexError`` on Unix and macOS when ``$XDG_DATA_DIRS`` or ``$XDG_CONFIG_DIRS`` holds only separators and whitespace, such as ``":"``. These values now fall back to the platform - defaults, and each entry is stripped of surrounding whitespace. :pr:`523` + defaults, and each entry is stripped of surrounding whitespace. :pr:`523` - by :user:`darrenhuai` and + :user:`gaborbernat`. + +.. _release-4-11-2: ********************* 4.11.2 (2026-08-10) ********************* +.. _release-4-11-2-fixed: + +Fixed +===== + - Stop :meth:`~platformdirs.PlatformDirs.iter_cache_dirs`, :meth:`~platformdirs.PlatformDirs.iter_state_dirs`, :meth:`~platformdirs.PlatformDirs.iter_log_dirs` and :meth:`~platformdirs.PlatformDirs.iter_runtime_dirs` yielding the - same directory twice on Unix when ``use_site_for_root`` is active - :pr:`469` fixed this for the config and data - iterators only. On macOS, :meth:`~platformdirs.PlatformDirs.iter_cache_dirs` now yields the Homebrew and - ``/Library/Caches`` entries separately rather than one ``os.pathsep``-joined string when ``multipath`` is set. - :pr:`520` + same directory twice on Unix when ``use_site_for_root`` is active - fixed this for the config and data iterators only. + On macOS, :meth:`~platformdirs.PlatformDirs.iter_cache_dirs` now yields the Homebrew and ``/Library/Caches`` entries + separately rather than one ``os.pathsep``-joined string when ``multipath`` is set. :pr:`469` :pr:`520` - by + :user:`viccie30` and :user:`darrenhuai`. + +.. _release-4-11-1: ********************* 4.11.1 (2026-08-07) ********************* +.. _release-4-11-1-fixed: + +Fixed +===== + - Fix :func:`~platformdirs.user_desktop_dir` on Windows builds without ``ctypes``. ``CSIDL_DESKTOPDIRECTORY`` appeared only in the ctypes lookup table, so the registry and environment variable resolvers raised ``ValueError`` for it. - :pr:`519` + :pr:`519` - by :user:`darrenhuai` and :user:`gaborbernat`. + +.. _release-4-11-0: ********************* 4.11.0 (2026-07-21) ********************* -- Declare support for Python 3.15 and run the test suite against it, currently in beta. :pr:`512` +.. _release-4-11-0-added: + +Added +===== + +- Declare support for Python 3.15 and run the test suite against it, currently in beta. :pr:`512` - by + :user:`gaborbernat`. + +.. _release-4-10-1: ********************* 4.10.1 (2026-07-18) ********************* +.. _release-4-10-1-performance: + +Performance +=========== + - Stop leaking memory on repeated Windows folder lookups. ``get_win_folder_via_ctypes`` defined a fresh ``ctypes`` structure on every call, and each one registered a pointer type that was never released; the resolver is now built - once and reused. :pr:`507` + once and reused. :pr:`507` - by :user:`gaborbernat`. + +.. _release-4-10-0: ********************* 4.10.0 (2026-05-28) ********************* +.. _release-4-10-0-added: + +Added +===== + - Add :func:`~platformdirs.user_publicshare_dir`, :func:`~platformdirs.user_templates_dir`, - :func:`~platformdirs.user_fonts_dir`, and :func:`~platformdirs.user_preference_dir` :pr:`491` -- Add :func:`~platformdirs.user_projects_dir` backed by ``$XDG_PROJECTS_DIR`` :pr:`490` -- Return only the first path from :func:`~platformdirs.site_config_path` on macOS when ``multipath`` is set :pr:`488` - - by :user:`lphuc2250gma` + :func:`~platformdirs.user_fonts_dir`, and :func:`~platformdirs.user_preference_dir`. :pr:`491` - by + :user:`gaborbernat`. +- Add :func:`~platformdirs.user_projects_dir` backed by ``$XDG_PROJECTS_DIR``. :pr:`490` - by :user:`gaborbernat`. + +.. _release-4-10-0-fixed: + +Fixed +===== + +- Return only the first path from :func:`~platformdirs.site_config_path` on macOS when ``multipath`` is set. :pr:`488` - + by :user:`lphuc2250gma`. + +.. _release-4-9-6: ******************** 4.9.6 (2026-04-09) ******************** +.. _release-4-9-6-fixed: + +Fixed +===== + - Fix macOS XDG variables leaking across :func:`~platformdirs.user_config_dir`, :func:`~platformdirs.user_data_dir`, and - :func:`~platformdirs.user_state_dir` when only some are set :pr:`473` - by :user:`Goddesen` + :func:`~platformdirs.user_state_dir` when only some are set. :pr:`473` - by :user:`Goddesen`. - Avoid duplicate site directories in Unix :meth:`~platformdirs.PlatformDirs.iter_config_dirs` and - :meth:`~platformdirs.PlatformDirs.iter_data_dirs` when ``use_site_for_root`` is active :pr:`469` - by :user:`viccie30` + :meth:`~platformdirs.PlatformDirs.iter_data_dirs` when ``use_site_for_root`` is active. :pr:`469` - by + :user:`viccie30`. + +.. _release-4-9-4: ******************** 4.9.4 (2026-03-05) ******************** -- Respect ``XDG_CONFIG_HOME`` when reading the user-dirs configuration :pr:`453` - by :user:`bysiber` +.. _release-4-9-4-fixed: + +Fixed +===== + +- Respect ``XDG_CONFIG_HOME`` when reading the user-dirs configuration. :pr:`453` - by :user:`bysiber`. - Create the directory in Android :func:`~platformdirs.user_log_dir` and :func:`~platformdirs.user_runtime_dir` when - ``ensure_exists`` is set :pr:`452` - by :user:`bysiber` + ``ensure_exists`` is set. :pr:`452` - by :user:`bysiber`. + +.. _release-4-9-2: ******************** 4.9.2 (2026-02-16) ******************** -- No user-facing changes +.. _release-4-9-1: ******************** 4.9.1 (2026-02-14) ******************** -- No user-facing changes +.. _release-4-9-0: ******************** 4.9.0 (2026-02-14) ******************** -- Add :func:`~platformdirs.site_bin_dir` :pr:`443` -- Add :func:`~platformdirs.site_applications_dir` :pr:`442` -- Use the correct runtime directory path on OpenBSD :pr:`440` +.. _release-4-9-0-added: + +Added +===== + +- Add :func:`~platformdirs.site_bin_dir`. :pr:`443` - by :user:`gaborbernat`. +- Add :func:`~platformdirs.site_applications_dir`. :pr:`442` - by :user:`gaborbernat`. + +.. _release-4-9-0-fixed: + +Fixed +===== + +- Use the correct runtime directory path on OpenBSD. :pr:`440` - by :user:`gaborbernat`. + +.. _release-4-8-0: ******************** 4.8.0 (2026-02-14) ******************** -- Add ``use_site_for_root`` to redirect ``user_*_dir`` to ``site_*_dir`` for root on Unix :pr:`426` -- Add :func:`~platformdirs.site_state_dir` for system-wide state :pr:`425` -- Add :func:`~platformdirs.site_log_dir` :pr:`424` -- Add :func:`~platformdirs.user_applications_dir` :pr:`432` -- Add :func:`~platformdirs.user_bin_dir` :pr:`430` -- Add ``PLATFORMDIRS_*`` environment variable overrides for Windows folder resolution :pr:`427` -- Add ``WIN_PD_OVERRIDE_*`` environment variable overrides for Windows folder resolution :pr:`428` +.. _release-4-8-0-added: + +Added +===== + +- Add ``use_site_for_root`` to redirect ``user_*_dir`` to ``site_*_dir`` for root on Unix. :pr:`426` - by + :user:`gaborbernat`. +- Add :func:`~platformdirs.site_state_dir` for system-wide state. :pr:`425` - by :user:`gaborbernat`. +- Add :func:`~platformdirs.site_log_dir`. :pr:`424` - by :user:`gaborbernat`. +- Add :func:`~platformdirs.user_applications_dir`. :pr:`432` - by :user:`gaborbernat`. +- Add :func:`~platformdirs.user_bin_dir`. :pr:`430` - by :user:`gaborbernat`. +- Add ``PLATFORMDIRS_*`` environment variable overrides for Windows folder resolution. :pr:`427` - by + :user:`gaborbernat`. +- Add ``WIN_PD_OVERRIDE_*`` environment variable overrides for Windows folder resolution. :pr:`428` - by + :user:`gaborbernat`. + +.. _release-4-8-0-fixed: + +Fixed +===== + - Yield individual site directories from :meth:`~platformdirs.PlatformDirs.iter_data_dirs` and - :meth:`~platformdirs.PlatformDirs.iter_config_dirs` on macOS :pr:`429` + :meth:`~platformdirs.PlatformDirs.iter_config_dirs` on macOS. :pr:`429` - by :user:`gaborbernat`. + +.. _release-4-7-1: ******************** 4.7.1 (2026-02-13) ******************** -- Avoid :exc:`FileNotFoundError` on Windows in sandboxed environments :pr:`422` +.. _release-4-7-1-fixed: + +Fixed +===== + +- Avoid :exc:`FileNotFoundError` on Windows in sandboxed environments. :pr:`422` - by :user:`gaborbernat`. + +.. _release-4-7-0: ******************** 4.7.0 (2026-02-12) ******************** -- Fall back to a temp directory when the Unix runtime dir is not writable :pr:`369` - by :user:`lengau` -- Use ``SHGetKnownFolderPath`` instead of the deprecated ``SHGetFolderPathW`` on Windows :pr:`380` - by :user:`moi15moi` +.. _release-4-7-0-fixed: + +Fixed +===== + +- Find relocated Windows Downloads folders and preserve long paths through ``SHGetKnownFolderPath``. :pr:`380` - by + :user:`moi15moi` and :user:`gaborbernat`. +- Fall back to a temp directory when the Unix runtime dir is not writable. :pr:`369` - by :user:`lengau` and + :user:`gaborbernat`. + +.. _release-4-6-0: ******************** 4.6.0 (2026-02-12) ******************** -- Honor XDG environment variables on macOS :pr:`375` - by :user:`Czaki` -- Fix :func:`~platformdirs.site_cache_dir` documentation :pr:`402` - by :user:`brianhelba` -- Fix an outdated link and correct a function docstring :pr:`398` - by :user:`joclement` +.. _release-4-6-0-fixed: + +Fixed +===== + +- Honor XDG environment variables on macOS. :pr:`375` - by :user:`Czaki` and :user:`gaborbernat`. + +.. _release-4-6-0-documentation: + +Documentation +============= + +- Fix :func:`~platformdirs.site_cache_dir` documentation. :pr:`402` - by :user:`brianhelba`. +- Fix an outdated link and correct a function docstring. :pr:`398` - by :user:`joclement`. + +.. _release-4-5-1: ******************** 4.5.1 (2025-12-05) ******************** -- Fix no-ctypes fallback on Windows :pr:`403` - by :user:`youknowone` +.. _release-4-5-1-fixed: + +Fixed +===== + +- Fix no-ctypes fallback on Windows. :pr:`403` - by :user:`youknowone`. + +.. _release-4-5-0: ******************** 4.5.0 (2025-10-08) ******************** -- Add support for Python 3.14 :pr:`382` - by :user:`hugovk` -- Drop support for Python 3.9 :pr:`389` -- Update Windows file paths in README :pr:`385` - by :user:`ParadaCarleton` +.. _release-4-5-0-added: + +Added +===== + +- Add support for Python 3.14. :pr:`382` - by :user:`hugovk`. +- Drop support for Python 3.9. :pr:`389` - by :user:`gaborbernat`. + +.. _release-4-5-0-documentation: + +Documentation +============= + +- Update Windows file paths in README. :pr:`385` - by :user:`ParadaCarleton`. + +.. _release-4-4-0: ******************** 4.4.0 (2025-08-26) ******************** -- Improve Homebrew path detection :pr:`370` - by :user:`daeho-ro` +.. _release-4-4-0-fixed: + +Fixed +===== + +- Improve Homebrew path detection. :pr:`370` - by :user:`daeho-ro`. + +.. _release-4-3-8: ******************** 4.3.8 (2025-05-07) ******************** -- Add missing examples and fix example order in README :pr:`355` - by :user:`gene1wood` +.. _release-4-3-8-documentation: + +Documentation +============= + +- Add missing examples and fix example order in README. :pr:`355` - by :user:`gene1wood`. + +.. _release-4-3-7: ******************** 4.3.7 (2025-03-19) ******************** -- Drop support for EOL Python 3.8 :pr:`330` - by :user:`hugovk` +.. _release-4-3-7-added: + +Added +===== + +- Drop support for EOL Python 3.8. :pr:`330` - by :user:`hugovk`. + +.. _release-4-3-6: ******************** 4.3.6 (2024-09-17) ******************** -- No user-facing changes +.. _release-4-3-5: ******************** 4.3.5 (2024-09-17) ******************** -- No user-facing changes +.. _release-4-3-4: ******************** 4.3.4 (2024-09-17) ******************** -- No user-facing changes +.. _release-4-3-3: ******************** 4.3.3 (2024-09-13) ******************** -- No user-facing changes +.. _release-4-3-2: ******************** 4.3.2 (2024-09-08) ******************** -- Fix multi-path returned from ``_path`` methods on macOS :pr:`299` - by :user:`matthewhughes934` +.. _release-4-3-2-fixed: + +Fixed +===== + +- Fix multi-path returned from ``_path`` methods on macOS. :pr:`299` - by :user:`matthewhughes934` and + :user:`gaborbernat`. + +.. _release-4-3-1: ******************** 4.3.1 (2024-09-07) ******************** -- No user-facing changes +.. _release-4-3-0: ******************** 4.3.0 (2024-09-07) ******************** -- Make :class:`~platformdirs.PlatformDirs` usable as a mypy superclass without breaking other type checkers :pr:`295` - - by :user:`Avasam` -- Add support for Python 3.13 :pr:`289` - by :user:`edgarrmondragon` +.. _release-4-3-0-added: + +Added +===== + +- Make :class:`~platformdirs.PlatformDirs` usable as a mypy superclass without breaking other type checkers. :pr:`295` - + by :user:`Avasam` and :user:`gaborbernat`. +- Add support for Python 3.13. :pr:`289` - by :user:`edgarrmondragon`. + +.. _release-4-2-2: ******************** 4.2.2 (2024-05-15) ******************** -- Fix Android detection when ``python-for-android`` is present :pr:`277` - by :user:`tmolitor-stud-tu` +.. _release-4-2-2-fixed: + +Fixed +===== + +- Fix Android detection when ``python-for-android`` is present. :pr:`277` - by :user:`tmolitor-stud-tu` and + :user:`gaborbernat`. + +.. _release-4-2-1: ******************** 4.2.1 (2024-04-23) ******************** -- Allow working without ctypes :pr:`275` - by :user:`youknowone` +.. _release-4-2-1-fixed: + +Fixed +===== + +- Allow working without ctypes. :pr:`275` - by :user:`youknowone`. + +.. _release-4-2-0: ******************** 4.2.0 (2024-01-31) ******************** -- Add convenience methods to iterate over both user and site dirs and paths :pr:`258` - by :user:`SpaceshipOperations` -- Fix two typos referencing ``XDG_DATA_DIR`` :pr:`256` - by :user:`Freed-Wu` +.. _release-4-2-0-added: + +Added +===== + +- Add convenience methods to iterate over both user and site dirs and paths. :pr:`258` - by :user:`SpaceshipOperations` + and :user:`gaborbernat`. + +.. _release-4-2-0-documentation: + +Documentation +============= + +- Fix two typos referencing ``XDG_DATA_DIR``. :pr:`256` - by :user:`Freed-Wu`. + +.. _release-4-1-0: ******************** 4.1.0 (2023-12-04) ******************** -- Drop support for EOL Python 3.7 :pr:`246` - by :user:`hugovk` -- Fix Linux :func:`~platformdirs.user_log_dir` example in README :pr:`245` - by :user:`dbohdan` +.. _release-4-1-0-added: + +Added +===== + +- Drop support for EOL Python 3.7. :pr:`246` - by :user:`hugovk`. + +.. _release-4-1-0-documentation: + +Documentation +============= + +- Fix Linux :func:`~platformdirs.user_log_dir` example in README. :pr:`245` - by :user:`dbohdan`. + +.. _release-4-0-0: ******************** 4.0.0 (2023-11-10) ******************** -- Revert :func:`~platformdirs.site_cache_dir` on UNIX to ``/var/cache`` instead of ``/var/tmp`` :pr:`239` - by - :user:`andersk` +.. _release-4-0-0-changes: + +Changes +======= + +- Revert :func:`~platformdirs.site_cache_dir` on UNIX to ``/var/cache`` instead of ``/var/tmp``. :pr:`239` - by + :user:`andersk`. + +.. _release-3-11-0: ********************* 3.11.0 (2023-10-02) ********************* -- Detect Homebrew-installed software on macOS :pr:`232` - by :user:`singingwolfboy` +.. _release-3-11-0-added: + +Added +===== + +- Detect Homebrew-installed software on macOS. :pr:`232` - by :user:`singingwolfboy`. + +.. _release-3-10-0: ********************* 3.10.0 (2023-07-29) ********************* -- Add :func:`~platformdirs.site_runtime_dir` :pr:`212` - by :user:`kemzeb` +.. _release-3-10-0-added: + +Added +===== + +- Add :func:`~platformdirs.site_runtime_dir`. :pr:`212` - by :user:`kemzeb`. + +.. _release-3-9-1: ******************** 3.9.1 (2023-07-15) ******************** -- Optionally create the opinionated ``log`` subdirectory in :func:`~platformdirs.user_log_dir` on Unix :pr:`208` - by - :user:`kemzeb` +.. _release-3-9-1-fixed: + +Fixed +===== + +- Optionally create the opinionated ``log`` subdirectory in :func:`~platformdirs.user_log_dir` on Unix. :pr:`208` - by + :user:`kemzeb`. + +.. _release-3-9-0: ******************** 3.9.0 (2023-07-15) ******************** -- Add :func:`~platformdirs.user_desktop_dir` and :func:`~platformdirs.user_desktop_path` :pr:`200` - by - :user:`lukacat10` +.. _release-3-9-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_desktop_dir` and :func:`~platformdirs.user_desktop_path`. :pr:`200` - by + :user:`lukacat10`. + +.. _release-3-8-1: ******************** 3.8.1 (2023-07-06) ******************** -- Provide a fallback for :func:`~platformdirs.user_runtime_dir` on BSD :pr:`201` - by :user:`RayyanAnsari` +.. _release-3-8-1-fixed: + +Fixed +===== + +- Provide a fallback for :func:`~platformdirs.user_runtime_dir` on BSD. :pr:`201` - by :user:`RayyanAnsari`. + +.. _release-3-8-0: ******************** 3.8.0 (2023-06-22) ******************** -- No user-facing changes +.. _release-3-7-0: ******************** 3.7.0 (2023-06-20) ******************** -- Return ``/var/run/user/$uid`` from :func:`~platformdirs.user_runtime_dir` on \*BSD :pr:`194` - by :user:`kemzeb` +.. _release-3-7-0-added: + +Added +===== + +- Return ``/var/run/user/$uid`` from :func:`~platformdirs.user_runtime_dir` on \*BSD. :pr:`194` - by :user:`kemzeb`. + +.. _release-3-6-0: ******************** 3.6.0 (2023-06-18) ******************** -- Add :func:`~platformdirs.user_downloads_dir` :pr:`192` - by :user:`cofiem` +.. _release-3-6-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_downloads_dir`. :pr:`192` - by :user:`cofiem`. + +.. _release-3-5-3: ******************** 3.5.3 (2023-06-09) ******************** -- Add support for Python 3.12 +.. _release-3-5-3-added: + +Added +===== + +- Add support for Python 3.12 - by :user:`gaborbernat`. + +.. _release-3-5-2: ******************** 3.5.2 (2023-06-09) ******************** -- No user-facing changes +.. _release-3-5-1: ******************** 3.5.1 (2023-05-11) ******************** -- Define ``getuid`` on all non-Windows platforms so :func:`~platformdirs.user_runtime_dir` works beyond Linux :pr:`183` +.. _release-3-5-1-fixed: + +Fixed +===== + +- Define ``getuid`` on all non-Windows platforms so :func:`~platformdirs.user_runtime_dir` works beyond Linux. :pr:`183` + - by :user:`gaborbernat` and :user:`mtelka`. + +.. _release-3-5-0: ******************** 3.5.0 (2023-04-27) ******************** -- Add :func:`~platformdirs.user_music_dir` :pr:`173` - by :user:`kemzeb` +.. _release-3-5-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_music_dir`. :pr:`173` - by :user:`kemzeb`. + +.. _release-3-4-0: ******************** 3.4.0 (2023-04-26) ******************** -- Add :func:`~platformdirs.user_videos_dir` :pr:`169` - by :user:`kemzeb` +.. _release-3-4-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_videos_dir`. :pr:`169` - by :user:`kemzeb`. + +.. _release-3-3-0: ******************** 3.3.0 (2023-04-25) ******************** -- Add :func:`~platformdirs.user_pictures_dir` :pr:`167` - by :user:`kemzeb` +.. _release-3-3-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_pictures_dir`. :pr:`167` - by :user:`kemzeb`. + +.. _release-3-2-0: ******************** 3.2.0 (2023-03-25) ******************** -- Add the ``ensure_exists`` option to create directories when they are missing :pr:`155` - by :user:`smsearcy` +.. _release-3-2-0-added: + +Added +===== + +- Add the ``ensure_exists`` option to create directories when they are missing. :pr:`155` - by :user:`smsearcy`. + +.. _release-3-1-1: ******************** 3.1.1 (2023-03-10) ******************** -- Point :func:`~platformdirs.site_cache_dir` at ``/var/tmp`` instead of write-protected ``/var/cache`` on Unix :pr:`148` - - by :user:`efiop` +.. _release-3-1-1-fixed: + +Fixed +===== + +- Point :func:`~platformdirs.site_cache_dir` at ``/var/tmp`` instead of write-protected ``/var/cache`` on Unix. + :pr:`148` - by :user:`efiop`. + +.. _release-3-1-0: ******************** 3.1.0 (2023-03-03) ******************** -- Add :func:`~platformdirs.site_cache_dir` :pr:`145` - by :user:`efiop` +.. _release-3-1-0-added: + +Added +===== + +- Add :func:`~platformdirs.site_cache_dir`. :pr:`145` - by :user:`efiop`. + +.. _release-3-0-0: ******************** 3.0.0 (2023-02-06) ******************** -- **BREAKING** Point macOS :func:`~platformdirs.user_config_dir` and :func:`~platformdirs.site_config_dir` at - ``*/Library/Application Support`` to mirror the data dirs, and drop the trailing slash from - :func:`~platformdirs.user_config_dir` and :func:`~platformdirs.user_data_dir` :pr:`137` - by :user:`ThomasWaldmann` +.. _release-3-0-0-fixed: + +Fixed +===== + +- Point macOS :func:`~platformdirs.user_config_dir` and :func:`~platformdirs.site_config_dir` at ``*/Library/Application + Support`` to mirror the data dirs, and drop the trailing slash from :func:`~platformdirs.user_config_dir` and + :func:`~platformdirs.user_data_dir`. :pr:`137` - by :user:`ThomasWaldmann` and :user:`gaborbernat`. + +.. _release-2-6-2: ******************** 2.6.2 (2022-12-28) ******************** -- Add ``typing-extensions`` as a dependency on Python < 3.8 :pr:`123` - by :user:`amacf` +.. _release-2-6-2-packaging: + +Packaging +========= + +- Add ``typing-extensions`` as a dependency on Python < 3.8. :pr:`123` - by :user:`amacf` and :user:`gaborbernat`. + +.. _release-2-6-1: ******************** 2.6.1 (2022-12-29) ******************** -- Detect Termux via ``$PREFIX`` when ``$SHELL`` is unset :pr:`115` - by :user:`Freed-Wu` +.. _release-2-6-1-fixed: + +Fixed +===== + +- Detect Termux via ``$PREFIX`` when ``$SHELL`` is unset. :pr:`115` - by :user:`Freed-Wu`. + +.. _release-2-6-0: ******************** 2.6.0 (2022-12-06) ******************** -- Point :func:`~platformdirs.user_log_dir` at :func:`~platformdirs.user_state_dir` on Linux per the XDG spec :pr:`108` - - by :user:`lordwelch` +.. _release-2-6-0-changes: + +Changes +======= + +- Point :func:`~platformdirs.user_log_dir` at :func:`~platformdirs.user_state_dir` on Linux per the XDG spec. :pr:`108` + - by :user:`lordwelch`. + +.. _release-2-5-4: ******************** 2.5.4 (2022-11-12) ******************** -- No user-facing changes +.. _release-2-5-3: ******************** 2.5.3 (2022-11-06) ******************** -- Declare support for Python 3.11 :pr:`103` - by :user:`hugovk` +.. _release-2-5-3-added: + +Added +===== + +- Declare support for Python 3.11. :pr:`103` - by :user:`hugovk`. + +.. _release-2-5-2: ******************** 2.5.2 (2022-04-18) ******************** -- Treat Android shells as Unix :pr:`72` +.. _release-2-5-2-fixed: + +Fixed +===== + +- Treat Android shells as Unix. :pr:`72` - by :user:`Blocked`. + +.. _release-2-5-1: ******************** 2.5.1 (2022-02-19) ******************** -- Work out of the box under Nuitka standalone builds :pr:`68` +.. _release-2-5-1-fixed: + +Fixed +===== + +- Work out of the box under Nuitka standalone builds. :pr:`68` - by :user:`gaborbernat` and :user:`Clouder0`. + +.. _release-2-5-0: ******************** 2.5.0 (2022-02-09) ******************** -- Support the Termux subsystem :pr:`63` - by :user:`YariKartoshe4ka` +.. _release-2-5-0-added: + +Added +===== + +- Support the Termux subsystem. :pr:`63` - by :user:`YariKartoshe4ka`. + +.. _release-2-4-1: ******************** 2.4.1 (2021-12-26) ******************** -- **BREAKING** Drop Python 3.6 support :pr:`52` +.. _release-2-4-1-added: + +Added +===== + +- Drop Python 3.6 support. :pr:`52` - by :user:`gaborbernat`. + +.. _release-2-4-0: ******************** 2.4.0 (2021-09-25) ******************** -- Add :func:`~platformdirs.user_documents_dir` :pr:`39` - by :user:`JuneStepp` +.. _release-2-4-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_documents_dir`. :pr:`39` - by :user:`JuneStepp`, Jeremy Stepp and :user:`gaborbernat`. + +.. _release-2-3-0: ******************** 2.3.0 (2021-08-30) ******************** -- Add :func:`~platformdirs.user_runtime_dir` for ``$XDG_RUNTIME_DIR`` :pr:`37` - by :user:`whonore` +.. _release-2-3-0-added: + +Added +===== + +- Add :func:`~platformdirs.user_runtime_dir` for ``$XDG_RUNTIME_DIR``. :pr:`37` - by :user:`whonore` and + :user:`gaborbernat`. + +.. _release-2-2-0: ******************** 2.2.0 (2021-07-29) ******************** -- Unix: fall back to the default when the ``$XDG_*`` environment variable is empty :pr:`30` - by :user:`papr` +.. _release-2-2-0-fixed: + +Fixed +===== + +- Unix: fall back to the default when the ``$XDG_*`` environment variable is empty. :pr:`30` - by :user:`papr` and + :user:`gaborbernat`. + +.. _release-2-1-0: ******************** 2.1.0 (2021-07-25) ******************** -- Add ``pathlib.Path``-returning ``*_path`` API alongside the string variants :pr:`27` - by :user:`papr` -- Add Android support :pr:`18` -- Add type annotations :pr:`20` - by :user:`domdfcoding` -- **BREAKING** Drop Python 2.7 and 3.5 support :pr:`14` - by :user:`domdfcoding` +.. _release-2-1-0-added: + +Added +===== + +- Add ``pathlib.Path``-returning ``*_path`` API alongside the string variants. :pr:`27` - by :user:`papr`. +- Add Android support. :pr:`18` - by :user:`gaborbernat` and :user:`YariKartoshe4ka`. +- Add type annotations. :pr:`20` - by :user:`domdfcoding`. +- Drop Python 2.7 and 3.5 support. :pr:`14` - by :user:`domdfcoding` and :user:`gaborbernat`. + +.. _release-2-0-2: ******************** 2.0.2 (2021-07-13) ******************** -- No user-facing changes +.. _release-2-0-0: ******************** 2.0.0 (2021-07-12) ******************** -- **BREAKING** Rename ``appdirs`` to ``platformdirs`` as part of the friendly fork -- **BREAKING** Remove support for end-of-life Pythons 2.6, 3.2, and 3.3 -- **BREAKING** Correct the config directory on macOS -- Add support for Python 3.7, 3.8, and 3.9 +.. _release-v2-0-0a3: + +*********************** + v2.0.0a3 (2021-05-13) +*********************** + +.. _release-v2-0-0a3-fixed: + +Fixed +===== + +- Stop expanding user paths twice for two macOS directory lookups. :pr:`1` - by :user:`ofek`. + +.. _release-v2-0-0a3-performance: + +Performance +=========== + +- Resolve platform-dependent functions at import to speed up directory lookups. :pr:`1` - by :user:`ofek`. + +.. _release-v2-0-0a2: + +*********************** + v2.0.0a2 (2021-05-13) +*********************** + +.. _release-v2-0-0a1: + +*********************** + v2.0.0a1 (2021-05-13) +*********************** + +.. _release-v2-0-0a1-added: + +Added +===== + +- Remove support for end-of-life Pythons 2.6, 3.2, and 3.3 - by :user:`Julian`. +- Add support for Python 3.7, 3.8, and 3.9 - by :user:`Julian`. +- Introduce ``platformdirs`` as a friendly fork of ``appdirs`` - by :user:`Julian`. diff --git a/docs/changelog/.gitkeep b/docs/changelog/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/docs/changelog/template.jinja2 b/docs/changelog/template.jinja2 deleted file mode 100644 index c93bd221..00000000 --- a/docs/changelog/template.jinja2 +++ /dev/null @@ -1,13 +0,0 @@ -{% set header = versiondata.version + " (" + versiondata.date + ")" %} -{{ "*" * (header | length + 1) }} - {{ header }} -{{ "*" * (header | length + 1) }} - -{% for section, _ in sections.items() %} -{% for category, val in definitions.items() if category in sections[section] %} -{% for text, values in sections[section][category].items() %} -- {{ text }}{{ (" " + values | join(", ")) if values else "" }} -{% endfor %} -{% endfor %} -{% endfor %} -{{ "\n" }} diff --git a/docs/conf.py b/docs/conf.py index 4e98c32b..997adb85 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -6,9 +6,15 @@ import os from datetime import UTC, datetime from pathlib import Path +from typing import TYPE_CHECKING + +from docutils import nodes from platformdirs.version import __version__ +if TYPE_CHECKING: + from sphinx.application import Sphinx + author = "The platformdirs team" project = "platformdirs" copyright = "2021, The platformdirs team" # ruff:ignore[builtin-variable-shadowing] @@ -62,3 +68,31 @@ exclude_patterns = ["changelog/*"] markdown_http_base = os.environ.get("READTHEDOCS_CANONICAL_URL", "") + + +def setup(app: Sphinx) -> None: + """Give repeated release categories stable, version-scoped labels.""" + app.connect("doctree-read", _label_release_categories, priority=400) + + +def _label_release_categories(app: Sphinx, document: nodes.document) -> None: + if app.env.current_document.docname != "changelog": + return + for section in document.findall(nodes.section): + if section[0].astext() not in { + "Added", + "Changes", + "Fixed", + "Documentation", + "Breaking changes", + "Security", + "Performance", + "Deprecated", + "Removed", + "Packaging", + }: + continue + if anchor := next((identifier for identifier in section["ids"] if identifier.startswith("release-")), None): + # Auto labels use the title source; each version needs its own category label. + section["ids"] = [anchor] + section[0].rawsource = anchor diff --git a/pylock.toml b/pylock.toml new file mode 100644 index 00000000..6d190888 --- /dev/null +++ b/pylock.toml @@ -0,0 +1,3047 @@ +lock-version = "1.0" +environments = [ + "python_version == \"3.15\" and sys_platform == \"linux\" and platform_machine == \"x86_64\" and implementation_name == \"cpython\" and platform_python_implementation == \"CPython\" and platform_system == \"Linux\"", +] +requires-python = ">=3.11" +dependency-groups = [ + "build", + "coverage", + "dev", + "docs", + "docs-core", + "fix", + "pkg-meta", + "project-runtime", + "release", + "release-news", + "release-notes", + "release-prepare", + "test", + "type", +] +default-groups = [ + "project-runtime", +] +created-by = "nab" + +[[packages]] +name = "accessible-pygments" +version = "0.0.5" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "pygments" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "accessible_pygments-0.0.5.tar.gz" +upload-time = 2024-05-10 11:23:10.216775+00:00 +url = "https://files.pythonhosted.org/packages/bc/c1/bbac6a50d02774f91572938964c582fff4270eee73ab822a4aeea4d8b11b/accessible_pygments-0.0.5.tar.gz" +size = 1377899 + +[packages.sdist.hashes] +sha256 = "40918d3e6a2b619ad424cb91e556bd3bd8865443d9f22f1dcdf79e33c8046872" + +[[packages.wheels]] +name = "accessible_pygments-0.0.5-py3-none-any.whl" +upload-time = 2024-05-10 11:23:08.421378+00:00 +url = "https://files.pythonhosted.org/packages/8d/3f/95338030883d8c8b91223b4e21744b04d11b161a3ef117295d8241f50ab4/accessible_pygments-0.0.5-py3-none-any.whl" +size = 1395903 + +[packages.wheels.hashes] +sha256 = "88ae3211e68a1d0b011504b2ffc1691feafce124b845bd072ab6f9f66f34d4b7" + +[[packages]] +name = "alabaster" +version = "1.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "alabaster-1.0.0.tar.gz" +upload-time = 2024-07-26 18:15:03.762569+00:00 +url = "https://files.pythonhosted.org/packages/a6/f8/d9c74d0daf3f742840fd818d69cfae176fa332022fd44e3469487d5a9420/alabaster-1.0.0.tar.gz" +size = 24210 + +[packages.sdist.hashes] +sha256 = "c00dca57bca26fa62a6d7d0a9fcce65f3e026e9bfe33e9c538fd3fbb2144fd9e" + +[[packages.wheels]] +name = "alabaster-1.0.0-py3-none-any.whl" +upload-time = 2024-07-26 18:15:02.050654+00:00 +url = "https://files.pythonhosted.org/packages/7e/b3/6b4067be973ae96ba0d615946e314c5ae35f9f993eca561b356540bb0c2b/alabaster-1.0.0-py3-none-any.whl" +size = 13929 + +[packages.wheels.hashes] +sha256 = "fc6786402dc3fcb2de3cabd5fe455a2db534b371124f1f21de8731783dec828b" + +[[packages]] +name = "annotated-types" +version = "0.8.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "annotated_types-0.8.0.tar.gz" +upload-time = 2026-07-23 20:16:13.995706+00:00 +url = "https://files.pythonhosted.org/packages/5f/56/a8120250d128bed162cd73c76d45f6ef9991f3e068f62a8ee060afa3104a/annotated_types-0.8.0.tar.gz" +size = 15893 + +[packages.sdist.hashes] +sha256 = "13b2beaad985e05e2d6407ee4c4f35590b11f8d693a258a561055cac8f64cab7" + +[[packages.wheels]] +name = "annotated_types-0.8.0-py3-none-any.whl" +upload-time = 2026-07-23 20:16:12.938651+00:00 +url = "https://files.pythonhosted.org/packages/99/91/8acff4f5e50511b911bbccb72b8628a49c68ce14148cd9f6431094859a90/annotated_types-0.8.0-py3-none-any.whl" +size = 13427 + +[packages.wheels.hashes] +sha256 = "f072f4d804ea359e4eaf198b1af7a8b0943881a87f31bb764f8bf219bb9419e0" + +[[packages]] +name = "appdirs" +version = "1.4.4" +marker = "\"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "appdirs-1.4.4.tar.gz" +upload-time = 2020-05-11 07:59:51.037820+00:00 +url = "https://files.pythonhosted.org/packages/d7/d8/05696357e0311f5b5c316d7b95f46c669dd9c15aaeecbb48c7d0aeb88c40/appdirs-1.4.4.tar.gz" +size = 13470 + +[packages.sdist.hashes] +sha256 = "7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41" + +[[packages.wheels]] +name = "appdirs-1.4.4-py2.py3-none-any.whl" +upload-time = 2020-05-11 07:59:49.499913+00:00 +url = "https://files.pythonhosted.org/packages/3b/00/2344469e2084fb287c2e0b57b72910309874c3245463acd6cf5e3db69324/appdirs-1.4.4-py2.py3-none-any.whl" +size = 9566 + +[packages.wheels.hashes] +sha256 = "a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128" + +[[packages]] +name = "attrs" +version = "26.1.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "attrs-26.1.0.tar.gz" +upload-time = 2026-03-19 14:22:25.026315+00:00 +url = "https://files.pythonhosted.org/packages/9a/8e/82a0fe20a541c03148528be8cac2408564a6c9a0cc7e9171802bc1d26985/attrs-26.1.0.tar.gz" +size = 952055 + +[packages.sdist.hashes] +sha256 = "d03ceb89cb322a8fd706d4fb91940737b6642aa36998fe130a9bc96c985eff32" + +[[packages.wheels]] +name = "attrs-26.1.0-py3-none-any.whl" +upload-time = 2026-03-19 14:22:23.645947+00:00 +url = "https://files.pythonhosted.org/packages/64/b4/17d4b0b2a2dc85a6df63d1157e028ed19f90d4cd97c36717afef2bc2f395/attrs-26.1.0-py3-none-any.whl" +size = 67548 + +[packages.wheels.hashes] +sha256 = "c647aa4a12dfbad9333ca4e71fe62ddc36f4e63b2d260a37a8b83d2f043ac309" + +[[packages]] +name = "babel" +version = "2.18.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "babel-2.18.0.tar.gz" +upload-time = 2026-02-01 12:30:56.078194+00:00 +url = "https://files.pythonhosted.org/packages/7d/b2/51899539b6ceeeb420d40ed3cd4b7a40519404f9baf3d4ac99dc413a834b/babel-2.18.0.tar.gz" +size = 9959554 + +[packages.sdist.hashes] +sha256 = "b80b99a14bd085fcacfa15c9165f651fbb3406e66cc603abf11c5750937c992d" + +[[packages.wheels]] +name = "babel-2.18.0-py3-none-any.whl" +upload-time = 2026-02-01 12:30:53.445172+00:00 +url = "https://files.pythonhosted.org/packages/77/f5/21d2de20e8b8b0408f0681956ca2c69f1320a3848ac50e6e7f39c6159675/babel-2.18.0-py3-none-any.whl" +size = 10196845 + +[packages.wheels.hashes] +sha256 = "e2b422b277c2b9a9630c1d7903c2a00d0830c409c59ac8cae9081c92f1aeba35" + +[[packages]] +name = "beautifulsoup4" +version = "4.15.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.7.0" +dependencies = [ + { name = "soupsieve" }, + { name = "typing-extensions" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "beautifulsoup4-4.15.0.tar.gz" +upload-time = 2026-06-07 16:44:20.453113+00:00 +url = "https://files.pythonhosted.org/packages/43/65/318323f98dbee45d42dff61d8f047181bc6f2268a9068cfad035a46be5af/beautifulsoup4-4.15.0.tar.gz" +size = 632571 + +[packages.sdist.hashes] +sha256 = "288e3ca7d54b06f2ac191970bc275c1939cb46d450b255bf6718b04aa37ab4f7" + +[[packages.wheels]] +name = "beautifulsoup4-4.15.0-py3-none-any.whl" +upload-time = 2026-06-07 16:44:21.566528+00:00 +url = "https://files.pythonhosted.org/packages/88/c6/92fcd42f1ba33e1184263f25bfabf3d27c383410470f169e4b8163bf9c17/beautifulsoup4-4.15.0-py3-none-any.whl" +size = 109924 + +[packages.wheels.hashes] +sha256 = "d6f88de62e1d4e38ecb1077eb9724cd0eff29d2a08ca16a401e9b9e93f117cf9" + +[[packages]] +name = "certifi" +version = "2026.10.18" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "certifi-2026.10.18.tar.gz" +upload-time = 2026-10-18 16:21:07.655710+00:00 +url = "https://files.pythonhosted.org/packages/7e/eb/a2aa1ac3ea30dd3f30ca57f40232138b6b0040719316ecb85daf61167771/certifi-2026.10.18.tar.gz" +size = 135227 + +[packages.sdist.hashes] +sha256 = "b9995d97b64d0431a5af837d8ca8cd6238104d1f319f04bd93ea43124d6c861e" + +[[packages.wheels]] +name = "certifi-2026.10.18-py3-none-any.whl" +upload-time = 2026-10-18 16:21:06.276884+00:00 +url = "https://files.pythonhosted.org/packages/08/ba/95dd616042484f7c83a06974388b37b837732740ee70bc5dc715b5fcd55a/certifi-2026.10.18-py3-none-any.whl" +size = 134093 + +[packages.wheels.hashes] +sha256 = "73191c47aaa79da394e8fee2dbc2ec827432cab56311122c9e47abf79e390f62" + +[[packages]] +name = "cffi" +version = "2.1.1" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "pycparser" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "cffi-2.1.1.tar.gz" +upload-time = 2026-08-03 21:21:18.939988+00:00 +url = "https://files.pythonhosted.org/packages/9e/ef/008a1939e372c06329a3fce4279c02f328488f3526744906eeec3da7ad5f/cffi-2.1.1.tar.gz" +size = 530807 + +[packages.sdist.hashes] +sha256 = "dd31f52ea1086513bb9df30f8fcee9b8918323ae067a3d5b78bc826a000712be" + +[[packages.wheels]] +name = "cffi-2.1.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-08-03 21:20:57.336082+00:00 +url = "https://files.pythonhosted.org/packages/44/16/29e6d01b388bef055ecd6ca8244b3f4d336bd09e92d5d892187b9601084e/cffi-2.1.1-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 221630 + +[packages.wheels.hashes] +sha256 = "aeae0e330c9f6acd681f647d46cefd30c29f93e3392882e792e82080c9691399" + +[[packages]] +name = "cfgv" +version = "3.5.0" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "cfgv-3.5.0.tar.gz" +upload-time = 2025-11-19 20:55:51.612035+00:00 +url = "https://files.pythonhosted.org/packages/4e/b5/721b8799b04bf9afe054a3899c6cf4e880fcf8563cc71c15610242490a0c/cfgv-3.5.0.tar.gz" +size = 7334 + +[packages.sdist.hashes] +sha256 = "d5b1034354820651caa73ede66a6294d6e95c1b00acc5e9b098e917404669132" + +[[packages.wheels]] +name = "cfgv-3.5.0-py2.py3-none-any.whl" +upload-time = 2025-11-19 20:55:50.744331+00:00 +url = "https://files.pythonhosted.org/packages/db/3c/33bac158f8ab7f89b2e59426d5fe2e4f63f7ed25df84c036890172b412b5/cfgv-3.5.0-py2.py3-none-any.whl" +size = 7445 + +[packages.wheels.hashes] +sha256 = "a8dc6b26ad22ff227d2634a65cb388215ce6cc96bbcc5cfde7641ae87e8dacc0" + +[[packages]] +name = "chardet" +version = "7.7.0" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "chardet-7.7.0.tar.gz" +upload-time = 2026-10-18 00:06:25.352198+00:00 +url = "https://files.pythonhosted.org/packages/47/92/3d893ac5d338b9a9af34c5b517d77492dcea8a10254254eead4215a96f3f/chardet-7.7.0.tar.gz" +size = 1008480 + +[packages.sdist.hashes] +sha256 = "0ba38a05201b0abf7570c12d8af45c30b2af835bd5cc52bfc7105082eda82c1e" + +[[packages.wheels]] +name = "chardet-7.7.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-10-18 00:06:13.977728+00:00 +url = "https://files.pythonhosted.org/packages/f9/12/2b3a006ae31a7ab4ccac11a00abb27af23b4a5d57ddb00e937375e747a2a/chardet-7.7.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 1660352 + +[packages.wheels.hashes] +sha256 = "42c4d8a2dc8abcc067417adc13c2f64f48482e48ce48e3af769b5a44214e5a5c" + +[[packages.wheels]] +name = "chardet-7.7.0-py3-none-any.whl" +upload-time = 2026-10-18 00:06:24.018863+00:00 +url = "https://files.pythonhosted.org/packages/cc/75/88a3eb36264375ff951bd2f9397c409727ab6aa6a18e1bd933851571d421/chardet-7.7.0-py3-none-any.whl" +size = 706680 + +[packages.wheels.hashes] +sha256 = "11cf9b719ea3675a2a7d8a3071bbe4d7ea24b26bfe39a51588d515ddd05cacad" + +[[packages]] +name = "charset-normalizer" +version = "3.5.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "charset_normalizer-3.5.2.tar.gz" +upload-time = 2026-09-30 04:39:23.398219+00:00 +url = "https://files.pythonhosted.org/packages/33/1c/f41d4e74c28ab327ff3acd36053f7ea506c55872d7a90b0fa71aa3ab0c89/charset_normalizer-3.5.2.tar.gz" +size = 172659 + +[packages.sdist.hashes] +sha256 = "39de2a259fc954455c57274dc94c79d5842774e1247a016aff30bc0efed0f4ef" + +[[packages.wheels]] +name = "charset_normalizer-3.5.2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-09-30 04:37:37.397915+00:00 +url = "https://files.pythonhosted.org/packages/a0/a1/4fbf5d0f0f1b2a080474c1cf9a2f12c4c6531bb0e8ba591055e846d2b4e9/charset_normalizer-3.5.2-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 257336 + +[packages.wheels.hashes] +sha256 = "3df041de8887954562c9b261cba85ca0e9ded74048daf125f45edcfaa4832229" + +[[packages.wheels]] +name = "charset_normalizer-3.5.2-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" +upload-time = 2026-09-30 04:38:28.032254+00:00 +url = "https://files.pythonhosted.org/packages/7e/84/371eac6b30bdbcbf2d632a1a01809103459216fcaae61b8b8d922c1bfb8a/charset_normalizer-3.5.2-cp37-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" +size = 253276 + +[packages.wheels.hashes] +sha256 = "1c50fe28bbc2ced33386f298650d91218076c05420e6cbd790b913adc41659e7" + +[[packages.wheels]] +name = "charset_normalizer-3.5.2-py3-none-any.whl" +upload-time = 2026-09-30 04:39:21.828049+00:00 +url = "https://files.pythonhosted.org/packages/fc/ad/d07d7862a62ffa6d79d68074d14823243dd235a77c45262acbf6adeb28bf/charset_normalizer-3.5.2-py3-none-any.whl" +size = 68872 + +[packages.wheels.hashes] +sha256 = "b6b751274acb69d77b3323d6b7dbaa3c7fdfc1eb829b7eb61d262f32e1af9685" + +[[packages]] +name = "check-wheel-contents" +version = "0.6.3" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "attrs" }, + { name = "click" }, + { name = "packaging" }, + { name = "pydantic" }, + { name = "wheel-filename" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "check_wheel_contents-0.6.3.tar.gz" +upload-time = 2025-08-02 14:01:45.546952+00:00 +url = "https://files.pythonhosted.org/packages/95/37/2b9e0d38c2f668791ffe8b97711185c364d91c027e47f189c371c2348d18/check_wheel_contents-0.6.3.tar.gz" +size = 586023 + +[packages.sdist.hashes] +sha256 = "10e6939e2fe4e6ce1edf2ff6ec6157808677e80782e78021ae139dd88473a442" + +[[packages.wheels]] +name = "check_wheel_contents-0.6.3-py3-none-any.whl" +upload-time = 2025-08-02 14:01:43.968164+00:00 +url = "https://files.pythonhosted.org/packages/be/05/f39fde9f31ef80b285ef5822fad4ddabf73fec62a1f02c5beb4b2f328972/check_wheel_contents-0.6.3-py3-none-any.whl" +size = 27541 + +[packages.wheels.hashes] +sha256 = "5ae39c8c434b972f0740d04610759168590713175aab584b012b1b84f6771874" + +[[packages]] +name = "click" +version = "8.5.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "click-8.5.0.tar.gz" +upload-time = 2026-08-26 13:33:14.560531+00:00 +url = "https://files.pythonhosted.org/packages/c7/0e/7fa0ef50764b67090eca4114772a2abf8b6148198475e54c660b97caeee6/click-8.5.0.tar.gz" +size = 382235 + +[packages.sdist.hashes] +sha256 = "ba0d2089de75ea0310e2dde03160e6ca10009947fb95a182f9b54021bb272e34" + +[[packages.wheels]] +name = "click-8.5.0-py3-none-any.whl" +upload-time = 2026-08-26 13:33:12.928043+00:00 +url = "https://files.pythonhosted.org/packages/58/50/6c0d534c5f134586a8e1ba4e330569e32f057e33372ae556463212fb4cd3/click-8.5.0-py3-none-any.whl" +size = 125251 + +[packages.wheels.hashes] +sha256 = "255bc9599cf7748b4b1a446ccc735421bd08a2ae529a8b88597d3de5664ee360" + +[[packages]] +name = "covdefaults" +version = "2.3.0" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "coverage" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "covdefaults-2.3.0.tar.gz" +upload-time = 2023-03-05 16:43:34.779146+00:00 +url = "https://files.pythonhosted.org/packages/44/ee/9a6f2611f72e4c5657ae5542a510cf4164d2c673687c0ea73bb1cbd85b4d/covdefaults-2.3.0.tar.gz" +size = 4835 + +[packages.sdist.hashes] +sha256 = "4e99f679f12d792bc62e5510fa3eb59546ed47bd569e36e4fddc4081c9c3ebf7" + +[[packages.wheels]] +name = "covdefaults-2.3.0-py2.py3-none-any.whl" +upload-time = 2023-03-05 16:43:33.245581+00:00 +url = "https://files.pythonhosted.org/packages/76/4c/823bc951445aa97e5a1b7e337690db3abf85212c8d138e170922e7916ac8/covdefaults-2.3.0-py2.py3-none-any.whl" +size = 5144 + +[packages.wheels.hashes] +sha256 = "2832961f6ffcfe4b57c338bc3418a3526f495c26fb9c54565409c5532f7c41be" + +[[packages]] +name = "coverage" +version = "7.16.2" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "coverage-7.16.2.tar.gz" +upload-time = 2026-09-27 12:29:01.118768+00:00 +url = "https://files.pythonhosted.org/packages/2f/55/d1eaf3e73781174340a00dc1ba2aee8a65f82fadb18e2797b192b6b3925b/coverage-7.16.2.tar.gz" +size = 971999 + +[packages.sdist.hashes] +sha256 = "ca64d9f1f384f151b9511bec01126072acd2f313439f8ed015a22d8790aab6fa" + +[[packages.wheels]] +name = "coverage-7.16.2-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" +upload-time = 2026-09-27 12:28:05.150722+00:00 +url = "https://files.pythonhosted.org/packages/de/29/48fca82a7ebf7ff7b2e35019cc9537e7f65e4d2aa1215cc5a8792c989251/coverage-7.16.2-cp315-cp315-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl" +size = 259106 + +[packages.wheels.hashes] +sha256 = "8fc15cc8d0d06e873c00ef18e1372d605f9aaf3de27d8c24e50782e75bc8b843" + +[[packages.wheels]] +name = "coverage-7.16.2-py3-none-any.whl" +upload-time = 2026-09-27 12:28:59.075376+00:00 +url = "https://files.pythonhosted.org/packages/3f/0c/7a64e1ac90541a8edf50daef0914848011fb057a5bf55284a4811e21939a/coverage-7.16.2-py3-none-any.whl" +size = 215754 + +[packages.wheels.hashes] +sha256 = "11d28e9123a9156cb405d8d27b44256c9a58fb5decc2073a8f17862057e3aa0f" + +[[packages]] +name = "cryptography" +version = "50.0.2" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = "!=3.9.0,!=3.9.1,>=3.9" +dependencies = [ + { name = "cffi" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "cryptography-50.0.2.tar.gz" +upload-time = 2026-09-30 15:30:04.884601+00:00 +url = "https://files.pythonhosted.org/packages/9d/af/182eb91b0df3fe75c4d9f26fe70684569566745f6ba7e5c9c73a862c5252/cryptography-50.0.2.tar.gz" +size = 880623 + +[packages.sdist.hashes] +sha256 = "7b46165bb56eb4704e2eaaf86f3c940d19154535d9b0ca7d6d590b04060e00d5" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-09-30 14:43:49.010540+00:00 +url = "https://files.pythonhosted.org/packages/21/69/64cef1f702bf6657e0cc186ed1a2891d50d29fb41586b254e1c07adea261/cryptography-50.0.2-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 4719841 + +[packages.wheels.hashes] +sha256 = "630ebfea3bf689d075f82316324ff7433dc447fe6bc1bfc76524b74b4a9567d2" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp311-abi3-manylinux_2_28_x86_64.whl" +upload-time = 2026-09-30 14:43:55.272150+00:00 +url = "https://files.pythonhosted.org/packages/1a/f1/b474e930c4d910328780e3940da76f5aa5cbc48ce1fc14e44d239d9ea9db/cryptography-50.0.2-cp311-abi3-manylinux_2_28_x86_64.whl" +size = 4753050 + +[packages.wheels.hashes] +sha256 = "4061c0079120205fb760c58acab6443e217307dcf05e3702cf970e0689972856" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp311-abi3-manylinux_2_34_x86_64.whl" +upload-time = 2026-09-30 14:44:04.545137+00:00 +url = "https://files.pythonhosted.org/packages/d3/69/2c833a049475e0a3444e94c7d0aca0aa51d166374a449b09e92ac98138de/cryptography-50.0.2-cp311-abi3-manylinux_2_34_x86_64.whl" +size = 4752576 + +[packages.wheels.hashes] +sha256 = "9dab55f57c74c3cad24c323bacbbd04be4705ba6eb0d92e920b1fc4837ed5079" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp315-abi3.abi3t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-09-30 14:44:45.769143+00:00 +url = "https://files.pythonhosted.org/packages/aa/a4/2c8d734e43d97f0842ee9f1b7b4bfb3d0cf5e19edebf43c2afe6675c2320/cryptography-50.0.2-cp315-abi3.abi3t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 4966465 + +[packages.wheels.hashes] +sha256 = "f2f9bd7f90c64fe89253f0a2c05e3c4856072660429ce8831b4235bf29403a67" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp315-abi3.abi3t-manylinux_2_28_x86_64.whl" +upload-time = 2026-09-30 14:44:53.379605+00:00 +url = "https://files.pythonhosted.org/packages/02/a8/8df951850d6b31d2a00218f19e2b3f999523437ed7a819df7fa427942fca/cryptography-50.0.2-cp315-abi3.abi3t-manylinux_2_28_x86_64.whl" +size = 5001199 + +[packages.wheels.hashes] +sha256 = "58a0c478eeca76fe5e07993c5a0703def34a6dc6a0cda4f5564639b33112ffe7" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp315-abi3.abi3t-manylinux_2_34_x86_64.whl" +upload-time = 2026-09-30 14:45:05.009031+00:00 +url = "https://files.pythonhosted.org/packages/24/95/83378121ef3eaaaf71d4b781577ff794acb39b9e1b87a3f156898c8497ed/cryptography-50.0.2-cp315-abi3.abi3t-manylinux_2_34_x86_64.whl" +size = 5000859 + +[packages.wheels.hashes] +sha256 = "e105ab60406787da31fccc883fc0f733af1efd78f0136a4599692c4083a73d0c" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-09-30 15:29:26.807001+00:00 +url = "https://files.pythonhosted.org/packages/bf/f1/1c1f6874e8550cfddd4b688ceb38cefb6ed15ceed224d56f133f3d88c214/cryptography-50.0.2-cp39-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 4749145 + +[packages.wheels.hashes] +sha256 = "ee247f5c245c9a2fe7c8e2214e295918838e44e00a45a6718451e4004219e767" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp39-abi3-manylinux_2_28_x86_64.whl" +upload-time = 2026-09-30 15:29:32.605292+00:00 +url = "https://files.pythonhosted.org/packages/4f/87/ef344a9e616871f2519c22d6afcda79ddd5d35e9592d95eb6e677608d055/cryptography-50.0.2-cp39-abi3-manylinux_2_28_x86_64.whl" +size = 4781387 + +[packages.wheels.hashes] +sha256 = "f21e8a22c8605750c7af886bab299a363721264061b4ac0a30efb73cfd58efc5" + +[[packages.wheels]] +name = "cryptography-50.0.2-cp39-abi3-manylinux_2_34_x86_64.whl" +upload-time = 2026-09-30 15:29:41.251208+00:00 +url = "https://files.pythonhosted.org/packages/40/cf/6b5c8e2fd9202d98988ab7cb5cc5c991704c4ad55f492ff408e4969f83f1/cryptography-50.0.2-cp39-abi3-manylinux_2_34_x86_64.whl" +size = 4780973 + +[packages.wheels.hashes] +sha256 = "1981f1db4630889b9ef7803fadef12b056f428cb6b85c27ba57b774793b6093c" + +[[packages]] +name = "cython" +version = "3.3.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "cython-3.3.0.tar.gz" +upload-time = 2026-08-22 05:16:39.493040+00:00 +url = "https://files.pythonhosted.org/packages/a9/d8/4981ef716ad0e3ff0d3ef383aefc6b03c4a88dee33b272bf8e0d833001ca/cython-3.3.0.tar.gz" +size = 3727515 + +[packages.sdist.hashes] +sha256 = "eed0d93fbca7087f143b42c34b05a825849bdf17f101572c2105acfa49aa88b8" + +[[packages.wheels]] +name = "cython-3.3.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-08-22 05:17:36.538454+00:00 +url = "https://files.pythonhosted.org/packages/c9/aa/4c0b6773ecf6bc1ec6cda7db8312a566611b330fb6dae87d740e44a47822/cython-3.3.0-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 3454285 + +[packages.wheels.hashes] +sha256 = "b447f6906e0555f05dc4742ef1f99091b1e5d9aa9f16616e772fbf9ff6271616" + +[[packages.wheels]] +name = "cython-3.3.0-py3-none-any.whl" +upload-time = 2026-08-22 05:16:36.741632+00:00 +url = "https://files.pythonhosted.org/packages/bf/77/67b0b24e45073a699610e50f00c18474ff9b09ea29ecc95083bdf5e60acd/cython-3.3.0-py3-none-any.whl" +size = 1349151 + +[packages.wheels.hashes] +sha256 = "9b24b5c8cd536946b62086fcafee6d5509d3f549f72d553d2336af87ffbe0da1" + +[[packages]] +name = "diff-cover" +version = "10.6.0" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "chardet" }, + { name = "jinja2" }, + { name = "pluggy" }, + { name = "pygments" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "diff_cover-10.6.0.tar.gz" +upload-time = 2026-09-22 00:43:00.885282+00:00 +url = "https://files.pythonhosted.org/packages/63/ef/479d5b18c5cd61c4fbb769c60d4829ea9d70aef1267e302d6de60deed7f3/diff_cover-10.6.0.tar.gz" +size = 107697 + +[packages.sdist.hashes] +sha256 = "8d1194dfb537f70480ac97c9c45dd40721cf4c326c9903fbe997db67a4db6195" + +[[packages.wheels]] +name = "diff_cover-10.6.0-py3-none-any.whl" +upload-time = 2026-09-22 00:42:59.593738+00:00 +url = "https://files.pythonhosted.org/packages/47/04/7130707bb385835cca7f168c80d812c9b42af9ae8230a26b3e21c9437c98/diff_cover-10.6.0-py3-none-any.whl" +size = 63351 + +[packages.wheels.hashes] +sha256 = "a701553060f72d59b81f9cb1645b75ef66204427eb9dd99873c91092220e52ce" + +[[packages]] +name = "distlib" +version = "0.4.4" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "distlib-0.4.4.tar.gz" +upload-time = 2026-10-16 13:56:34.203008+00:00 +url = "https://files.pythonhosted.org/packages/68/bc/d36966de7304047a1001a7559fbf266c464bb5d8cc85464536ef8c9bcc32/distlib-0.4.4.tar.gz" +size = 621304 + +[packages.sdist.hashes] +sha256 = "ca4175b4ac7f71223cc30ed7248c45d2b38c2439d8ee6e498ab67ed63cf3508d" + +[[packages.wheels]] +name = "distlib-0.4.4-py2.py3-none-any.whl" +upload-time = 2026-10-16 13:56:32.053304+00:00 +url = "https://files.pythonhosted.org/packages/c1/2b/238f02a4927fa2e27aa995371d240a468b52e42eae44a678434aff736b38/distlib-0.4.4-py2.py3-none-any.whl" +size = 472099 + +[packages.wheels.hashes] +sha256 = "cf09d55b1e85a89576b036aeb71550bfd68320f3f21761ca329eadadad918638" + +[[packages]] +name = "docutils" +version = "0.22.4" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "docutils-0.22.4.tar.gz" +upload-time = 2025-12-18 19:00:26.443107+00:00 +url = "https://files.pythonhosted.org/packages/ae/b6/03bb70946330e88ffec97aefd3ea75ba575cb2e762061e0e62a213befee8/docutils-0.22.4.tar.gz" +size = 2291750 + +[packages.sdist.hashes] +sha256 = "4db53b1fde9abecbb74d91230d32ab626d94f6badfc575d6db9194a49df29968" + +[[packages.wheels]] +name = "docutils-0.22.4-py3-none-any.whl" +upload-time = 2025-12-18 19:00:18.077803+00:00 +url = "https://files.pythonhosted.org/packages/02/10/5da547df7a391dcde17f59520a231527b8571e6f46fc8efb02ccb370ab12/docutils-0.22.4-py3-none-any.whl" +size = 633196 + +[packages.wheels.hashes] +sha256 = "d0013f540772d1420576855455d050a2180186c91c15779301ac2ccb3eeb68de" + +[[packages]] +name = "filelock" +version = "4.2.4" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.11" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "filelock-4.2.4.tar.gz" +upload-time = 2026-10-19 01:57:51.001795+00:00 +url = "https://files.pythonhosted.org/packages/d8/28/3893324bcadf8f89b1616637468d766af3f625008c0735bf704fdfa86617/filelock-4.2.4.tar.gz" +size = 652444 + +[packages.sdist.hashes] +sha256 = "c6d8663535e1650ee430507b4ffbac7b464dd64b7647ea0112a9f406499d163d" + +[[packages.wheels]] +name = "filelock-4.2.4-py3-none-any.whl" +upload-time = 2026-10-19 01:57:49.419460+00:00 +url = "https://files.pythonhosted.org/packages/e0/1b/5e74289a1878e666bb4b65fe5805a04cafcac2aa5f519ef1ead67ef91c56/filelock-4.2.4-py3-none-any.whl" +size = 162475 + +[packages.wheels.hashes] +sha256 = "301241438c57936ef93f4243a94f2559022268bfcf9b375a9a72eb0f8db8358e" + +[[packages]] +name = "furo" +version = "2025.12.19" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.8" +dependencies = [ + { name = "accessible-pygments" }, + { name = "beautifulsoup4" }, + { name = "pygments" }, + { name = "sphinx" }, + { name = "sphinx-basic-ng" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "furo-2025.12.19.tar.gz" +upload-time = 2025-12-19 17:34:40.889109+00:00 +url = "https://files.pythonhosted.org/packages/ec/20/5f5ad4da6a5a27c80f2ed2ee9aee3f9e36c66e56e21c00fde467b2f8f88f/furo-2025.12.19.tar.gz" +size = 1661473 + +[packages.sdist.hashes] +sha256 = "188d1f942037d8b37cd3985b955839fea62baa1730087dc29d157677c857e2a7" + +[[packages.wheels]] +name = "furo-2025.12.19-py3-none-any.whl" +upload-time = 2025-12-19 17:34:38.905692+00:00 +url = "https://files.pythonhosted.org/packages/f4/b2/50e9b292b5cac13e9e81272c7171301abc753a60460d21505b606e15cf21/furo-2025.12.19-py3-none-any.whl" +size = 339262 + +[packages.wheels.hashes] +sha256 = "bb0ead5309f9500130665a26bee87693c41ce4dbdff864dbfb6b0dae4673d24f" + +[[packages]] +name = "hatch-fancy-pypi-readme" +version = "25.1.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.8" +dependencies = [ + { name = "hatchling" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "hatch_fancy_pypi_readme-25.1.0.tar.gz" +upload-time = 2025-05-01 10:34:42.989334+00:00 +url = "https://files.pythonhosted.org/packages/f3/0f/aed57c301f339936eb91cb4d8c1e5088a101081854bd3ec18a889df32365/hatch_fancy_pypi_readme-25.1.0.tar.gz" +size = 29701 + +[packages.sdist.hashes] +sha256 = "9c58ed3dff90d51f43414ce37009ad1d5b0f08ffc9fc216998a06380f01c0045" + +[[packages.wheels]] +name = "hatch_fancy_pypi_readme-25.1.0-py3-none-any.whl" +upload-time = 2025-05-01 10:34:41.204793+00:00 +url = "https://files.pythonhosted.org/packages/58/b4/ad71e051b34f1935783de37beffee16e343ff2514b204dc515f9e939d4af/hatch_fancy_pypi_readme-25.1.0-py3-none-any.whl" +size = 10046 + +[packages.wheels.hashes] +sha256 = "ce0134c40d63d874ac48f48ccc678b8f3b62b8e50e9318520d2bffc752eedaf3" + +[[packages]] +name = "hatch-vcs" +version = "0.5.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "hatchling" }, + { name = "setuptools-scm" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "hatch_vcs-0.5.0.tar.gz" +upload-time = 2025-05-27 05:16:04.490926+00:00 +url = "https://files.pythonhosted.org/packages/6b/b0/4cc743d38adbee9d57d786fa496ed1daadb17e48589b6da8fa55717a0746/hatch_vcs-0.5.0.tar.gz" +size = 11424 + +[packages.sdist.hashes] +sha256 = "0395fa126940340215090c344a2bf4e2a77bcbe7daab16f41b37b98c95809ff9" + +[[packages.wheels]] +name = "hatch_vcs-0.5.0-py3-none-any.whl" +upload-time = 2025-05-27 05:16:03.184909+00:00 +url = "https://files.pythonhosted.org/packages/5f/48/1f85cee4b7b4f40b9b814b1febbc661bda6ced9649e410a0b74f6e415dd0/hatch_vcs-0.5.0-py3-none-any.whl" +size = 8507 + +[packages.wheels.hashes] +sha256 = "b49677dbdc597460cc22d01b27ab3696f5e16a21ecf2700fb01bc28e1f2a04a7" + +[[packages]] +name = "hatchling" +version = "1.32.4" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "packaging" }, + { name = "pathspec" }, + { name = "pluggy" }, + { name = "tomlkit" }, + { name = "trove-classifiers" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "hatchling-1.32.4.tar.gz" +upload-time = 2026-09-20 22:48:45.398505+00:00 +url = "https://files.pythonhosted.org/packages/f6/97/b5312f01a8c6daf729a9d272dd442e0c546dbcc630495788786c4b567ed0/hatchling-1.32.4.tar.gz" +size = 58065 + +[packages.sdist.hashes] +sha256 = "c4468f73144c054d2aab4ef0f0378c43b9878bf07f8ffd6b79690e970d375f07" + +[[packages.wheels]] +name = "hatchling-1.32.4-py3-none-any.whl" +upload-time = 2026-09-20 22:48:44.190681+00:00 +url = "https://files.pythonhosted.org/packages/5f/80/91f51f439c05d4ec4623c22928ce16a938d6d793bf709477830823497859/hatchling-1.32.4-py3-none-any.whl" +size = 78748 + +[packages.wheels.hashes] +sha256 = "08ecf7548fb48205e7f213d70c71e67b8271b7242093dc3f1da578b42c734a2c" + +[[packages]] +name = "id" +version = "1.6.1" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "urllib3" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "id-1.6.1.tar.gz" +upload-time = 2026-02-04 16:19:41.260133+00:00 +url = "https://files.pythonhosted.org/packages/6d/04/c2156091427636080787aac190019dc64096e56a23b7364d3c1764ee3a06/id-1.6.1.tar.gz" +size = 18088 + +[packages.sdist.hashes] +sha256 = "d0732d624fb46fd4e7bc4e5152f00214450953b9e772c182c1c22964def1a069" + +[[packages.wheels]] +name = "id-1.6.1-py3-none-any.whl" +upload-time = 2026-02-04 16:19:40.051745+00:00 +url = "https://files.pythonhosted.org/packages/42/77/de194443bf38daed9452139e960c632b0ef9f9a5dd9ce605fdf18ca9f1b1/id-1.6.1-py3-none-any.whl" +size = 14689 + +[packages.wheels.hashes] +sha256 = "f5ec41ed2629a508f5d0988eda142e190c9c6da971100612c4de9ad9f9b237ca" + +[[packages]] +name = "identify" +version = "2.6.20" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "identify-2.6.20.tar.gz" +upload-time = 2026-09-26 20:29:07.187608+00:00 +url = "https://files.pythonhosted.org/packages/53/35/d70c0006c7cee65999ea94a6273e60b2094f600a3d8b71b04318253fc643/identify-2.6.20.tar.gz" +size = 99681 + +[packages.sdist.hashes] +sha256 = "ad729860a923858d26917c2f4fb0a1d83d27a75b1e090c06440c573f048f3285" + +[[packages.wheels]] +name = "identify-2.6.20-py2.py3-none-any.whl" +upload-time = 2026-09-26 20:29:06.054092+00:00 +url = "https://files.pythonhosted.org/packages/fa/70/fffc9613501877c0a10a1ef73a165e6ded3e53f6e7502227fef56d973933/identify-2.6.20-py2.py3-none-any.whl" +size = 99506 + +[packages.wheels.hashes] +sha256 = "6a16b69b93187244e0548cbfd25b3e4a6f9a7a2ad784625c3bec2b8d27b81aaa" + +[[packages]] +name = "idna" +version = "3.20" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "idna-3.20.tar.gz" +upload-time = 2026-09-17 14:11:04.752193+00:00 +url = "https://files.pythonhosted.org/packages/f5/08/8eea9d4b8302028f3abb2c0813953f7aec26d33b7a8960ed760e65ff29fa/idna-3.20.tar.gz" +size = 216463 + +[packages.sdist.hashes] +sha256 = "a7db850025b95ded1eae8a46181a1a6c56c92c96f0e2b005d9ff8dc0210cab44" + +[[packages.wheels]] +name = "idna-3.20-py3-none-any.whl" +upload-time = 2026-09-17 14:11:03.168153+00:00 +url = "https://files.pythonhosted.org/packages/58/a2/bb081bab032533a855d44de1d56f8e8426114ff1ba5d1f07a438a0a654f8/idna-3.20-py3-none-any.whl" +size = 69583 + +[packages.wheels.hashes] +sha256 = "ab7ae7122974553370f0bdb919e1a960b2cd1bc1ef0276416d896db81c14582c" + +[[packages]] +name = "imagesize" +version = "2.0.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "imagesize-2.0.1.tar.gz" +upload-time = 2026-08-24 12:35:19.130667+00:00 +url = "https://files.pythonhosted.org/packages/fb/5e/513ff06670c84e7b9887c1fdf61b2d42b4f574a831f2f1d2222023049d8a/imagesize-2.0.1.tar.gz" +size = 1883774 + +[packages.sdist.hashes] +sha256 = "b2ba6a4dea487a7ebcd53248d3476aca449d30db12a2dde5e0c5ca9624fd77e5" + +[[packages.wheels]] +name = "imagesize-2.0.1-py3-none-any.whl" +upload-time = 2026-08-24 12:35:12.548956+00:00 +url = "https://files.pythonhosted.org/packages/01/f9/575c8d760eae1fc99651b7cc5efd96ad5379ca4d6b53750b0fb4fe983f34/imagesize-2.0.1-py3-none-any.whl" +size = 14794 + +[packages.wheels.hashes] +sha256 = "ea0c9a0384df69ed86a943a15cde37d0360b82491b3910dc2215e202e62b5b02" + +[[packages]] +name = "iniconfig" +version = "2.3.1" +marker = "\"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "iniconfig-2.3.1.tar.gz" +upload-time = 2026-10-06 22:48:38.076390+00:00 +url = "https://files.pythonhosted.org/packages/01/e1/2069291243c926a2ff1cd706c7f3eeb9b62144bf60f77c9fb9ff2fb26bd3/iniconfig-2.3.1.tar.gz" +size = 21209 + +[packages.sdist.hashes] +sha256 = "67f4b9c50da0dedf52af349e7749a80a9057a5031199791b906c3bb3ae878960" + +[[packages.wheels]] +name = "iniconfig-2.3.1-py3-none-any.whl" +upload-time = 2026-10-06 22:48:36.959685+00:00 +url = "https://files.pythonhosted.org/packages/56/43/4ca9e49d27a1fcf6bece6f6aec0ea46bb9112489b93d4b688fb415457bdb/iniconfig-2.3.1-py3-none-any.whl" +size = 7552 + +[packages.wheels.hashes] +sha256 = "9121e2c1fdb355232495be3194c8dfe87ccc2d5dee45947b78e68f499790d7a7" + +[[packages]] +name = "jaraco-classes" +version = "3.4.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.8" +dependencies = [ + { name = "more-itertools" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jaraco.classes-3.4.0.tar.gz" +upload-time = 2024-03-31 07:27:36.643708+00:00 +url = "https://files.pythonhosted.org/packages/06/c0/ed4a27bc5571b99e3cff68f8a9fa5b56ff7df1c2251cc715a652ddd26402/jaraco.classes-3.4.0.tar.gz" +size = 11780 + +[packages.sdist.hashes] +sha256 = "47a024b51d0239c0dd8c8540c6c7f484be3b8fcf0b2d85c13825780d3b3f3acd" + +[[packages.wheels]] +name = "jaraco.classes-3.4.0-py3-none-any.whl" +upload-time = 2024-03-31 07:27:34.792832+00:00 +url = "https://files.pythonhosted.org/packages/7f/66/b15ce62552d84bbfcec9a4873ab79d993a1dd4edb922cbfccae192bd5b5f/jaraco.classes-3.4.0-py3-none-any.whl" +size = 6777 + +[packages.wheels.hashes] +sha256 = "f662826b6bed8cace05e7ff873ce0f9283b5c924470fe664fff1c2f00f581790" + +[[packages]] +name = "jaraco-context" +version = "6.1.2" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jaraco_context-6.1.2.tar.gz" +upload-time = 2026-03-20 22:13:33.922545+00:00 +url = "https://files.pythonhosted.org/packages/af/50/4763cd07e722bb6285316d390a164bc7e479db9d90daa769f22578f698b4/jaraco_context-6.1.2.tar.gz" +size = 16801 + +[packages.sdist.hashes] +sha256 = "f1a6c9d391e661cc5b8d39861ff077a7dc24dc23833ccee564b234b81c82dfe3" + +[[packages.wheels]] +name = "jaraco_context-6.1.2-py3-none-any.whl" +upload-time = 2026-03-20 22:13:32.808832+00:00 +url = "https://files.pythonhosted.org/packages/f2/58/bc8954bda5fcda97bd7c19be11b85f91973d67a706ed4a3aec33e7de22db/jaraco_context-6.1.2-py3-none-any.whl" +size = 7871 + +[packages.wheels.hashes] +sha256 = "bf8150b79a2d5d91ae48629d8b427a8f7ba0e1097dd6202a9059f29a36379535" + +[[packages]] +name = "jaraco-functools" +version = "4.6.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "more-itertools" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jaraco_functools-4.6.0.tar.gz" +upload-time = 2026-07-14 01:28:02.544761+00:00 +url = "https://files.pythonhosted.org/packages/6c/1f/c23395957d41ccf27c4e535c3d334c4051e5395b3752057ba4cbaec35c56/jaraco_functools-4.6.0.tar.gz" +size = 20837 + +[packages.sdist.hashes] +sha256 = "880c577ec9720b3a052d5bc611fb9f2269b3d87902ef42440df443b88e443280" + +[[packages.wheels]] +name = "jaraco_functools-4.6.0-py3-none-any.whl" +upload-time = 2026-07-14 01:28:01.590470+00:00 +url = "https://files.pythonhosted.org/packages/02/36/ecc85bc96c273dc8a11273ed4782272975e6338d4a3e9228621175edf0e3/jaraco_functools-4.6.0-py3-none-any.whl" +size = 11677 + +[packages.wheels.hashes] +sha256 = "99e3dc0060c5cbe8fcd1cdb36258e2a65ca40f1566b2033b12abb1bb44dd3c30" + +[[packages]] +name = "jeepney" +version = "0.9.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jeepney-0.9.0.tar.gz" +upload-time = 2025-02-27 18:51:01.684959+00:00 +url = "https://files.pythonhosted.org/packages/7b/6f/357efd7602486741aa73ffc0617fb310a29b588ed0fd69c2399acbb85b0c/jeepney-0.9.0.tar.gz" +size = 106758 + +[packages.sdist.hashes] +sha256 = "cf0e9e845622b81e4a28df94c40345400256ec608d0e55bb8a3feaa9163f5732" + +[[packages.wheels]] +name = "jeepney-0.9.0-py3-none-any.whl" +upload-time = 2025-02-27 18:51:00.104279+00:00 +url = "https://files.pythonhosted.org/packages/b2/a3/e137168c9c44d18eff0376253da9f1e9234d0239e0ee230d2fee6cea8e55/jeepney-0.9.0-py3-none-any.whl" +size = 49010 + +[packages.wheels.hashes] +sha256 = "97e5714520c16fc0a45695e5365a2e11b81ea79bba796e26f9f1d178cb182683" + +[[packages]] +name = "jinja2" +version = "3.1.6" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "markupsafe" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "jinja2-3.1.6.tar.gz" +upload-time = 2025-03-05 20:05:02.478302+00:00 +url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz" +size = 245115 + +[packages.sdist.hashes] +sha256 = "0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d" + +[[packages.wheels]] +name = "jinja2-3.1.6-py3-none-any.whl" +upload-time = 2025-03-05 20:05:00.369721+00:00 +url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl" +size = 134899 + +[packages.wheels.hashes] +sha256 = "85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67" + +[[packages]] +name = "keyring" +version = "25.7.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "jaraco-classes" }, + { name = "jaraco-context" }, + { name = "jaraco-functools" }, + { name = "jeepney" }, + { name = "secretstorage" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "keyring-25.7.0.tar.gz" +upload-time = 2025-11-16 16:26:09.482176+00:00 +url = "https://files.pythonhosted.org/packages/43/4b/674af6ef2f97d56f0ab5153bf0bfa28ccb6c3ed4d1babf4305449668807b/keyring-25.7.0.tar.gz" +size = 63516 + +[packages.sdist.hashes] +sha256 = "fe01bd85eb3f8fb3dd0405defdeac9a5b4f6f0439edbb3149577f244a2e8245b" + +[[packages.wheels]] +name = "keyring-25.7.0-py3-none-any.whl" +upload-time = 2025-11-16 16:26:08.402146+00:00 +url = "https://files.pythonhosted.org/packages/81/db/e655086b7f3a705df045bf0933bdd9c2f79bb3c97bfef1384598bb79a217/keyring-25.7.0-py3-none-any.whl" +size = 39160 + +[packages.wheels.hashes] +sha256 = "be4a0b195f149690c166e850609a477c532ddbfbaed96a404d4e43f8d5e2689f" + +[[packages]] +name = "markdown-it-py" +version = "4.2.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "mdurl" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "markdown_it_py-4.2.0.tar.gz" +upload-time = 2026-05-07 12:08:28.360612+00:00 +url = "https://files.pythonhosted.org/packages/06/ff/7841249c247aa650a76b9ee4bbaeae59370dc8bfd2f6c01f3630c35eb134/markdown_it_py-4.2.0.tar.gz" +size = 82454 + +[packages.sdist.hashes] +sha256 = "04a21681d6fbb623de53f6f364d352309d4094dd4194040a10fd51833e418d49" + +[[packages.wheels]] +name = "markdown_it_py-4.2.0-py3-none-any.whl" +upload-time = 2026-05-07 12:08:27.182789+00:00 +url = "https://files.pythonhosted.org/packages/b3/81/4da04ced5a082363ecfa159c010d200ecbd959ae410c10c0264a38cac0f5/markdown_it_py-4.2.0-py3-none-any.whl" +size = 91687 + +[packages.wheels.hashes] +sha256 = "9f7ebbcd14fe59494226453aed97c1070d83f8d24b6fc3a3bcf9a38092641c4a" + +[[packages]] +name = "markupsafe" +version = "3.0.4" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "markupsafe-3.0.4.tar.gz" +upload-time = 2026-10-02 23:07:22.290270+00:00 +url = "https://files.pythonhosted.org/packages/38/9b/e422a865e1d5d57d0e509b4e0bf1c1a70a7f6382c29a5aa428df994c8bc8/markupsafe-3.0.4.tar.gz" +size = 153777 + +[packages.sdist.hashes] +sha256 = "2e9ad7dd851bf45fab9f75cbff4cb493fee9979e8d8c7c9c3ee119022518edd6" + +[[packages.wheels]] +name = "markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +upload-time = 2026-10-02 23:06:22.524416+00:00 +url = "https://files.pythonhosted.org/packages/82/96/ef49135ce260db4ca4a12b119ed468449cd248db6b1468e2112b546d7a2e/markupsafe-3.0.4-cp315-cp315-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl" +size = 23111 + +[packages.wheels.hashes] +sha256 = "925f929d6b59a8b3f8b8c6ac363cd0af7eecc81efb3071770b3c6717c450a369" + +[[packages]] +name = "mdformat" +version = "1.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdformat-1.0.0.tar.gz" +upload-time = 2025-10-16 12:05:03.695033+00:00 +url = "https://files.pythonhosted.org/packages/3f/05/32b5e14b192b0a8a309f32232c580aefedd9d06017cb8fe8fce34bec654c/mdformat-1.0.0.tar.gz" +size = 56953 + +[packages.sdist.hashes] +sha256 = "4954045fcae797c29f86d4ad879e43bb151fa55dbaf74ac6eaeacf1d45bb3928" + +[[packages.wheels]] +name = "mdformat-1.0.0-py3-none-any.whl" +upload-time = 2025-10-16 12:05:02.607432+00:00 +url = "https://files.pythonhosted.org/packages/54/9a/8fe71b95985ca7a4001effbcc58e5a07a1f2a2884203f74dcf48a3b08315/mdformat-1.0.0-py3-none-any.whl" +size = 53288 + +[packages.wheels.hashes] +sha256 = "bca015d65a1d063a02e885a91daee303057bc7829c2cd37b2075a50dbb65944b" + +[[packages]] +name = "mdformat-gfm" +version = "1.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, + { name = "mdformat" }, + { name = "mdit-py-plugins" }, + { name = "wcwidth" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdformat_gfm-1.0.0.tar.gz" +upload-time = 2025-10-16 09:12:22.402429+00:00 +url = "https://files.pythonhosted.org/packages/56/6f/a626ebb142a290474401b67e2d61e73ce096bf7798ee22dfe6270f924b3f/mdformat_gfm-1.0.0.tar.gz" +size = 10112 + +[packages.sdist.hashes] +sha256 = "d1d49a409a6acb774ce7635c72d69178df7dce1dc8cdd10e19f78e8e57b72623" + +[[packages.wheels]] +name = "mdformat_gfm-1.0.0-py3-none-any.whl" +upload-time = 2025-10-16 09:12:21.276157+00:00 +url = "https://files.pythonhosted.org/packages/e6/18/6bc2189b744dd383cad03764f41f30352b1278d2205096f77a29c0b327ad/mdformat_gfm-1.0.0-py3-none-any.whl" +size = 10970 + +[packages.wheels.hashes] +sha256 = "7305a50efd2a140d7c83505b58e3ac5df2b09e293f9bbe72f6c7bee8c678b005" + +[[packages]] +name = "mdit-py-plugins" +version = "0.6.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "markdown-it-py" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdit_py_plugins-0.6.1.tar.gz" +upload-time = 2026-05-13 09:03:38.910230+00:00 +url = "https://files.pythonhosted.org/packages/59/fc/f8d0863f8862f25602c0404d75568e89fb6b4109804645e5cdfb1be5cf56/mdit_py_plugins-0.6.1.tar.gz" +size = 56114 + +[packages.sdist.hashes] +sha256 = "a2bca0f039f39dbd35fb74ae1b5f998608c437463371f0ff7f49a19a17a114d0" + +[[packages.wheels]] +name = "mdit_py_plugins-0.6.1-py3-none-any.whl" +upload-time = 2026-05-13 09:03:37.760000+00:00 +url = "https://files.pythonhosted.org/packages/a5/69/6da5581c6a7fede7dc261bf4e67d6adca4196f176b43288b55b3db395b6e/mdit_py_plugins-0.6.1-py3-none-any.whl" +size = 66663 + +[packages.wheels.hashes] +sha256 = "214c82fb2ac524472ab6a5bcab1de80f73b50443e187f401bfd77efbc7c6481d" + +[[packages]] +name = "mdurl" +version = "0.1.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "mdurl-0.1.2.tar.gz" +upload-time = 2022-08-14 12:40:10.846281+00:00 +url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz" +size = 8729 + +[packages.sdist.hashes] +sha256 = "bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba" + +[[packages.wheels]] +name = "mdurl-0.1.2-py3-none-any.whl" +upload-time = 2022-08-14 12:40:09.779676+00:00 +url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl" +size = 9979 + +[packages.wheels.hashes] +sha256 = "84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8" + +[[packages]] +name = "more-itertools" +version = "11.2.1" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.11" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "more_itertools-11.2.1.tar.gz" +upload-time = 2026-10-14 18:50:30.407709+00:00 +url = "https://files.pythonhosted.org/packages/52/b8/c63995bebbb9ac9c059350e0fb8c82c2420c85aeca7d34e40aecf3df9281/more_itertools-11.2.1.tar.gz" +size = 154133 + +[packages.sdist.hashes] +sha256 = "cbf08fd0af284dc69718b9b76a8e6203df624d70209ea511e4219d350c856f63" + +[[packages.wheels]] +name = "more_itertools-11.2.1-py3-none-any.whl" +upload-time = 2026-10-14 18:50:29.116732+00:00 +url = "https://files.pythonhosted.org/packages/5d/57/3c4b1c6f2e0cc29ba023802458ea3d2a996f87085559e4a5f2192d549532/more_itertools-11.2.1-py3-none-any.whl" +size = 74405 + +[packages.wheels.hashes] +sha256 = "35a7377edd1dd6608dcb2cdf534ded55ea32d49448875ad042cd3f879fb1ded0" + +[[packages]] +name = "nh3" +version = "0.3.7" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "nh3-0.3.7.tar.gz" +upload-time = 2026-08-23 14:26:30.728660+00:00 +url = "https://files.pythonhosted.org/packages/18/2f/022b27146d52d24b1b353b003359134788ecbcd6fcdf6283adbd57c0fbc8/nh3-0.3.7.tar.gz" +size = 25662 + +[packages.sdist.hashes] +sha256 = "71860d01c16f4d8c72e334e0674beb2b0899dbd0bf760de18932ef4390303848" + +[[packages.wheels]] +name = "nh3-0.3.7-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-08-23 14:26:17.272038+00:00 +url = "https://files.pythonhosted.org/packages/a6/ed/c5510c615dce55b6fcc364aa1838142f938beed64f5e4927490dfcaf4405/nh3-0.3.7-cp38-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 832161 + +[packages.wheels.hashes] +sha256 = "70f5ac8626e899a4bab0ef74ca2f5bd602f49c7b739e6e5026b4afc6d63dac42" + +[[packages]] +name = "nodeenv" +version = "1.11.0" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "nodeenv-1.11.0.tar.gz" +upload-time = 2026-09-26 11:29:21.367929+00:00 +url = "https://files.pythonhosted.org/packages/9a/8e/105de02c1322cfada6d9710d9146ef8026419d433c9d08359a2d35805811/nodeenv-1.11.0.tar.gz" +size = 99301 + +[packages.sdist.hashes] +sha256 = "3ce8fe5b71d16e8af7039ca65257354100bc772965d6bc549070649e53b1b146" + +[[packages.wheels]] +name = "nodeenv-1.11.0-py2.py3-none-any.whl" +upload-time = 2026-09-26 11:29:19.933601+00:00 +url = "https://files.pythonhosted.org/packages/54/c8/12811c9b48fde162bb72b6f2e78fada9a247a09d7bb5be2050a5d099c77b/nodeenv-1.11.0-py2.py3-none-any.whl" +size = 34277 + +[packages.wheels.hashes] +sha256 = "edaa16e6c14d7cf395d75d4bbd5a26390f4dc06501a33b4e76282b02cc688a25" + +[[packages]] +name = "packaging" +version = "26.3" +marker = "\"build\" in dependency_groups or \"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"fix\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "packaging-26.3.tar.gz" +upload-time = 2026-08-04 18:15:28.737071+00:00 +url = "https://files.pythonhosted.org/packages/7d/fa/3944b40b07da9ce895c0e6303a5ab7d53da063554f534556b134a54d6093/packaging-26.3.tar.gz" +size = 313412 + +[packages.sdist.hashes] +sha256 = "94edc256424af38762eb31306eed28beb9f0efc50a8837492c9d6fd6004aed79" + +[[packages.wheels]] +name = "packaging-26.3-py3-none-any.whl" +upload-time = 2026-08-04 18:15:27.159957+00:00 +url = "https://files.pythonhosted.org/packages/63/34/ba1c580383c9eada3711951fef0795c80b829a078d72188184bcab9dd527/packaging-26.3-py3-none-any.whl" +size = 129956 + +[packages.wheels.hashes] +sha256 = "d7193f7c8e4e93f444fde0262bf90af30e16fa0ad0ad44cb553c87339b23cd1c" + +[[packages]] +name = "pathspec" +version = "1.1.1" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pathspec-1.1.1.tar.gz" +upload-time = 2026-04-27 01:46:08.907631+00:00 +url = "https://files.pythonhosted.org/packages/5a/82/42f767fc1c1143d6fd36efb827202a2d997a375e160a71eb2888a925aac1/pathspec-1.1.1.tar.gz" +size = 135180 + +[packages.sdist.hashes] +sha256 = "17db5ecd524104a120e173814c90367a96a98d07c45b2e10c2f3919fff91bf5a" + +[[packages.wheels]] +name = "pathspec-1.1.1-py3-none-any.whl" +upload-time = 2026-04-27 01:46:07.060850+00:00 +url = "https://files.pythonhosted.org/packages/f1/d9/7fb5aa316bc299258e68c73ba3bddbc499654a07f151cba08f6153988714/pathspec-1.1.1-py3-none-any.whl" +size = 57328 + +[packages.wheels.hashes] +sha256 = "a00ce642f577bf7f473932318056212bc4f8bfdf53128c78bbd5af0b9b20b189" + +[[packages]] +name = "platformdirs" +version = "4.13.5" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.11" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "platformdirs-4.13.5.tar.gz" +upload-time = 2026-10-19 01:02:11.778459+00:00 +url = "https://files.pythonhosted.org/packages/58/e6/d0abbb256b44e6a05748c6942511ff67db8dbb068de0c35b24bf1b395b09/platformdirs-4.13.5.tar.gz" +size = 62362 + +[packages.sdist.hashes] +sha256 = "05831adf87d392760f4b5c3a0a95579ab5a10b18b9b9bd43680dcb47544788a0" + +[[packages.wheels]] +name = "platformdirs-4.13.5-py3-none-any.whl" +upload-time = 2026-10-19 01:02:10.170818+00:00 +url = "https://files.pythonhosted.org/packages/6c/8a/1d8cb3842909dc193a73835adedf412e32e18f8ffd59f43983949622fe6f/platformdirs-4.13.5-py3-none-any.whl" +size = 32779 + +[packages.wheels.hashes] +sha256 = "53d3ec4280b815c1e0b02edad7f9ee8fda1ba9c0865dd9c2e6e63849ce82fc1e" + +[[packages]] +name = "pluggy" +version = "1.7.0" +marker = "\"build\" in dependency_groups or \"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pluggy-1.7.0.tar.gz" +upload-time = 2026-10-15 09:50:58.343484+00:00 +url = "https://files.pythonhosted.org/packages/bf/db/7fc19e6f2dc92a966727031389fc2e08b558f0f25eb7403c1119ad4713cd/pluggy-1.7.0.tar.gz" +size = 123304 + +[packages.sdist.hashes] +sha256 = "d1eaa46ebb595891b860ab086b4d09c8588af65ebd4361b8e8f4bb8920b90ba8" + +[[packages.wheels]] +name = "pluggy-1.7.0-py3-none-any.whl" +upload-time = 2026-10-15 09:50:56.808462+00:00 +url = "https://files.pythonhosted.org/packages/40/9e/2b38731e0fc536806f16490e1a12d7f0dc2a1235aa8cc07bcc75416a7daa/pluggy-1.7.0-py3-none-any.whl" +size = 27082 + +[packages.wheels.hashes] +sha256 = "7dd7b0d8832ba3cb632c306926ded123429211b83641b35dc5c41ad2d34f9bec" + +[[packages]] +name = "pre-commit" +version = "4.7.0" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.11" +dependencies = [ + { name = "cfgv" }, + { name = "identify" }, + { name = "nodeenv" }, + { name = "pyyaml" }, + { name = "virtualenv" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pre_commit-4.7.0.tar.gz" +upload-time = 2026-10-12 20:45:40.320969+00:00 +url = "https://files.pythonhosted.org/packages/3a/c3/6965c2690ddce885ec75121572d065a5b94c5a5d8d3e657927ecda9fd715/pre_commit-4.7.0.tar.gz" +size = 198120 + +[packages.sdist.hashes] +sha256 = "1f3deee12b914c8fa184bd2b5953391c2e4f36763e403d4a23dc9983fa7c6e86" + +[[packages.wheels]] +name = "pre_commit-4.7.0-py2.py3-none-any.whl" +upload-time = 2026-10-12 20:45:38.858255+00:00 +url = "https://files.pythonhosted.org/packages/eb/83/ce0a196e4f7b20b11ce3aa1fc72fb973f64b7628d51c1b8aebad37fb7f81/pre_commit-4.7.0-py2.py3-none-any.whl" +size = 226261 + +[packages.wheels.hashes] +sha256 = "2e229038ad3656081b70c27913157e4b636ef306f643f024a8a8e3f0f7b2f877" + +[[packages]] +name = "pre-commit-uv" +version = "4.4.0" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.11" +dependencies = [ + { name = "pre-commit" }, + { name = "uv" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pre_commit_uv-4.4.0.tar.gz" +upload-time = 2026-10-11 00:27:45.724147+00:00 +url = "https://files.pythonhosted.org/packages/95/3c/65ca92a8343efcf16107824d01c4664bb9a2b2e8b7fb4efc954375e56c26/pre_commit_uv-4.4.0.tar.gz" +size = 7591 + +[packages.sdist.hashes] +sha256 = "8e1b91485fdaba0673fc0f81229cab364c00fb6193b5fe0bcee2862b1a4ce1d4" + +[[packages.wheels]] +name = "pre_commit_uv-4.4.0-py3-none-any.whl" +upload-time = 2026-10-11 00:27:44.627800+00:00 +url = "https://files.pythonhosted.org/packages/29/fa/d5fe0626ce7a70510e6fbf2c6a9f6da4f1cbc42b86542ada1eae0eea6b55/pre_commit_uv-4.4.0-py3-none-any.whl" +size = 6209 + +[packages.wheels.hashes] +sha256 = "9012b09950a50efdcfb03b95355e1f65c14f9a5cb425d12c6bf2c6d6807617d7" + +[[packages]] +name = "prek" +version = "0.5.6" +marker = "\"release-prepare\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "prek-0.5.6.tar.gz" +upload-time = 2026-10-19 05:46:52.314250+00:00 +url = "https://files.pythonhosted.org/packages/4f/96/c4062bcaebdabfa945d07c424fb8c05d53a72d4f3fdcf255b1188abbb150/prek-0.5.6.tar.gz" +size = 579962 + +[packages.sdist.hashes] +sha256 = "87a8c19f873b96be809b4368959ed908cfa06255dba15082d0fb91173e9293bc" + +[[packages.wheels]] +name = "prek-0.5.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-10-19 05:46:42.326947+00:00 +url = "https://files.pythonhosted.org/packages/e1/f7/04e08d2343ce1d54c5da879e2dfea7df20f3140b1b2023a937fac87fa545/prek-0.5.6-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 6165929 + +[packages.wheels.hashes] +sha256 = "aabec01beeb372bcdc48f6b339021bc33c07edf477b337fc92dc5d3b01f99150" + +[[packages]] +name = "pycparser" +version = "3.11" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pycparser-3.11.tar.gz" +upload-time = 2026-10-09 12:56:59.539345+00:00 +url = "https://files.pythonhosted.org/packages/da/a8/c5fdbeee588bb8ada9458774f43adf1bdd30bd59157055142183e769a024/pycparser-3.11.tar.gz" +size = 113796 + +[packages.sdist.hashes] +sha256 = "d875f09c3507d00e1aba0eecc6dcadc1352f30fff09dc6bff2f1c2935e97c2bc" + +[[packages.wheels]] +name = "pycparser-3.11-py3-none-any.whl" +upload-time = 2026-10-09 12:56:58.131173+00:00 +url = "https://files.pythonhosted.org/packages/90/11/0e6f11117525ff0eec40ebac3d313376f102df93ca44ad9e893ee85e4f89/pycparser-3.11-py3-none-any.whl" +size = 51178 + +[packages.wheels.hashes] +sha256 = "51d5a8ba2be0bbe440b99d2112604c95bbbc3c2748a64260186c541e1729cd80" + +[[packages]] +name = "pydantic" +version = "2.14.1" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "annotated-types" }, + { name = "pydantic-core" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pydantic-2.14.1.tar.gz" +upload-time = 2026-10-11 18:37:55.396662+00:00 +url = "https://files.pythonhosted.org/packages/7c/0b/8e10b2e693af8ec54346a14caf36221334775975a747c9ceaa3f8371d96d/pydantic-2.14.1.tar.gz" +size = 900362 + +[packages.sdist.hashes] +sha256 = "94f478203dd03404682a1ada216965651dd74b1d2d5ffd62e00e0837caab5c26" + +[[packages.wheels]] +name = "pydantic-2.14.1-py3-none-any.whl" +upload-time = 2026-10-11 18:37:53.437059+00:00 +url = "https://files.pythonhosted.org/packages/35/ea/a56b9fe5066f3537b7882f77e9c5dfb26d8c2eefdaed9b5fc73d57b4dc22/pydantic-2.14.1-py3-none-any.whl" +size = 488106 + +[packages.wheels.hashes] +sha256 = "9195d967ec791692a04438115466764fb8b9a27b31f14a760437694f40d6b454" + +[[packages]] +name = "pydantic-core" +version = "2.50.1" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "typing-extensions" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pydantic_core-2.50.1.tar.gz" +upload-time = 2026-10-11 18:35:44.820993+00:00 +url = "https://files.pythonhosted.org/packages/a6/24/af4ec4be49fbc810f35b0bdcacc3d433b56bbfa469fd3bfd4ae116cd9bf1/pydantic_core-2.50.1.tar.gz" +size = 513515 + +[packages.sdist.hashes] +sha256 = "e50d7b94baac6c7d09927fa5ca5800a0c7ee5015c7fcff65beb3a1931b5a6e09" + +[[packages.wheels]] +name = "pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-10-11 18:34:15.560294+00:00 +url = "https://files.pythonhosted.org/packages/b8/0d/1b1149f60a00ea21ba5f70e28acbd40feb4598af414f80f53c921fac07c9/pydantic_core-2.50.1-cp315-cp315-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 2159961 + +[packages.wheels.hashes] +sha256 = "7689580e72a642ab5ec64d5f55b2e33636fa43b4ebe63c0c2c965ef307c7d1aa" + +[[packages]] +name = "pygments" +version = "2.21.0" +marker = "\"coverage\" in dependency_groups or \"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pygments-2.21.0.tar.gz" +upload-time = 2026-08-17 08:02:48.824391+00:00 +url = "https://files.pythonhosted.org/packages/49/2e/ced460408999b33da6b31b0021b0f37d329e202d4169aeb164493778f25b/pygments-2.21.0.tar.gz" +size = 5005329 + +[packages.sdist.hashes] +sha256 = "610ca751c9bc2492b38eb9a38a7fbc93edbbb2d7182edaf34e66ae493dee5c8c" + +[[packages.wheels]] +name = "pygments-2.21.0-py3-none-any.whl" +upload-time = 2026-08-17 08:02:44.912148+00:00 +url = "https://files.pythonhosted.org/packages/71/46/17f022dd3e953bf20a04a028a21ec746d942f8d2af30fa0f124fa0e6a684/pygments-2.21.0-py3-none-any.whl" +size = 1250147 + +[packages.wheels.hashes] +sha256 = "2363c69b61c4a97c838da3b130dcd6468f4848992b21a82f2a63ec34377137d9" + +[[packages]] +name = "pytest" +version = "9.1.1" +marker = "\"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "iniconfig" }, + { name = "packaging" }, + { name = "pluggy" }, + { name = "pygments" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pytest-9.1.1.tar.gz" +upload-time = 2026-06-19 10:58:32.857420+00:00 +url = "https://files.pythonhosted.org/packages/e4/47/b9efed96c114afcfa3c9d3fe98a76a1d14c74a9e266d397cf6eb64be5e01/pytest-9.1.1.tar.gz" +size = 1636369 + +[packages.sdist.hashes] +sha256 = "1088fbde8f2b49d95a549a195707afa7a76a3ce9bcadc26b6d71f0ffda5fe313" + +[[packages.wheels]] +name = "pytest-9.1.1-py3-none-any.whl" +upload-time = 2026-06-19 10:58:31.347074+00:00 +url = "https://files.pythonhosted.org/packages/24/25/1de2678b631f5a49215c6c96fff41ba892b0a34df68d6d80292b1b48aa7f/pytest-9.1.1-py3-none-any.whl" +size = 386536 + +[packages.wheels.hashes] +sha256 = "37a86b45efb9a47a61a36449063e8e18d0cab3161329fc099eb21783169c4f0c" + +[[packages]] +name = "pytest-cov" +version = "7.1.0" +marker = "\"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "coverage" }, + { name = "pluggy" }, + { name = "pytest" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pytest_cov-7.1.0.tar.gz" +upload-time = 2026-03-21 20:11:16.284275+00:00 +url = "https://files.pythonhosted.org/packages/b1/51/a849f96e117386044471c8ec2bd6cfebacda285da9525c9106aeb28da671/pytest_cov-7.1.0.tar.gz" +size = 55592 + +[packages.sdist.hashes] +sha256 = "30674f2b5f6351aa09702a9c8c364f6a01c27aae0c1366ae8016160d1efc56b2" + +[[packages.wheels]] +name = "pytest_cov-7.1.0-py3-none-any.whl" +upload-time = 2026-03-21 20:11:14.438324+00:00 +url = "https://files.pythonhosted.org/packages/9d/7a/d968e294073affff457b041c2be9868a40c1c71f4a35fcc1e45e5493067b/pytest_cov-7.1.0-py3-none-any.whl" +size = 22876 + +[packages.wheels.hashes] +sha256 = "a0461110b7865f9a271aa1b51e516c9a95de9d696734a2f71e3e78f46e1d4678" + +[[packages]] +name = "pytest-mock" +version = "3.17.0" +marker = "\"dev\" in dependency_groups or \"test\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "pytest" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pytest_mock-3.17.0.tar.gz" +upload-time = 2026-10-17 16:21:42.435701+00:00 +url = "https://files.pythonhosted.org/packages/97/c2/28b9f5b955ff2bcd4727a6f768e2ca9b586cd7c37b95ea5f7b9b873ac7b3/pytest_mock-3.17.0.tar.gz" +size = 43064 + +[packages.sdist.hashes] +sha256 = "e36576e0985e01027e999891e7a966c67822d40c89ef1b4c8b6e22737e3590b4" + +[[packages.wheels]] +name = "pytest_mock-3.17.0-py3-none-any.whl" +upload-time = 2026-10-17 16:21:41.265482+00:00 +url = "https://files.pythonhosted.org/packages/e8/ea/47fbdc8f37410956fd445720e927589b1e2a47772c5f28109f0ce2fa26d9/pytest_mock-3.17.0-py3-none-any.whl" +size = 11248 + +[packages.wheels.hashes] +sha256 = "1b82aa4b37137248bd687055e109723debeb07b489de1565297dc9589c5f2d6b" + +[[packages]] +name = "python-discovery" +version = "1.6.4" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "filelock" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "python_discovery-1.6.4.tar.gz" +upload-time = 2026-10-19 01:45:14.855085+00:00 +url = "https://files.pythonhosted.org/packages/f3/ee/cf608372c88ce2c136ee13c69ab6f667dbc0d0c1176af188b4ddc8853e66/python_discovery-1.6.4.tar.gz" +size = 89883 + +[packages.sdist.hashes] +sha256 = "bc70d31f0ec5de11eda13d4d64c16e24b3506a65984684f2b6c98cb83b2ea9df" + +[[packages.wheels]] +name = "python_discovery-1.6.4-py3-none-any.whl" +upload-time = 2026-10-19 01:45:13.668192+00:00 +url = "https://files.pythonhosted.org/packages/60/91/1aa70d3dfcab0dbcf88a2cbc3bce7f7c69562287a90216e617eaa4937e25/python_discovery-1.6.4-py3-none-any.whl" +size = 39385 + +[packages.wheels.hashes] +sha256 = "530179cc51a1816d512b15635b3dc931295ae12efb183783ad31190a5d425d2b" + +[[packages]] +name = "pyyaml" +version = "6.0.3" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"fix\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "pyyaml-6.0.3.tar.gz" +upload-time = 2025-09-25 21:33:16.546886+00:00 +url = "https://files.pythonhosted.org/packages/05/8e/961c0007c59b8dd7729d542c61a4d537767a59645b82a0b521206e1e25c2/pyyaml-6.0.3.tar.gz" +size = 130960 + +[packages.sdist.hashes] +sha256 = "d76623373421df22fb4cf8817020cbb7ef15c725b9d5e45f17e189bfc384190f" + +[[packages]] +name = "readme-renderer" +version = "46.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "docutils" }, + { name = "nh3" }, + { name = "pygments" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "readme_renderer-46.0.tar.gz" +upload-time = 2026-08-28 15:18:32.490778+00:00 +url = "https://files.pythonhosted.org/packages/25/d7/9309494fad74ee831d4546f69325b5519f37c6dfb2d9ba495db8c6d4f4ca/readme_renderer-46.0.tar.gz" +size = 38382 + +[packages.sdist.hashes] +sha256 = "af3e964914f6310a33ff67b72a4bdd940bed8d7c3bdecd2d14f40edf284bfe90" + +[[packages.wheels]] +name = "readme_renderer-46.0-py3-none-any.whl" +upload-time = 2026-08-28 15:18:31.132970+00:00 +url = "https://files.pythonhosted.org/packages/4b/72/ac5ca81fe9121fcaa9d828d21017cba00a16a98e4ea5fb60c878f93dda4f/readme_renderer-46.0-py3-none-any.whl" +size = 14239 + +[packages.wheels.hashes] +sha256 = "d0dae1f74bb273b534770cb4cccb6bb78735540afdb03c2146f4e19dcd412560" + +[[packages]] +name = "release-creator" +version = "4.1.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.15" +dependencies = [ + { name = "docutils" }, + { name = "markdown-it-py" }, + { name = "mdformat" }, + { name = "mdformat-gfm" }, + { name = "packaging" }, + { name = "pyyaml" }, + { name = "towncrier" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "release_creator-4.1.0.tar.gz" +upload-time = 2026-10-26 18:24:45.805437+00:00 +url = "https://files.pythonhosted.org/packages/7f/fd/05d7f3c604476a238d67d5aaa2a4085312e7078c193dbd7ad99ad48d560d/release_creator-4.1.0.tar.gz" +size = 186016 + +[packages.sdist.hashes] +sha256 = "c783037f5ca2efc16fa7cccfb1c2abf0a442f116a63ca82bd7bfb7e2a8343a15" + +[[packages.wheels]] +name = "release_creator-4.1.0-py3-none-any.whl" +upload-time = 2026-10-26 18:24:44.353933+00:00 +url = "https://files.pythonhosted.org/packages/30/d0/38480e99025c021d07e0710af02547562dfadbd798bef26dc01869a3f81e/release_creator-4.1.0-py3-none-any.whl" +size = 52922 + +[packages.wheels.hashes] +sha256 = "67deae16d11ac261a1512f18a22c0cf13418f43afc3e56cb74e58ad4422062e3" + +[[packages]] +name = "requests" +version = "2.34.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "certifi" }, + { name = "charset-normalizer" }, + { name = "idna" }, + { name = "urllib3" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "requests-2.34.2.tar.gz" +upload-time = 2026-05-14 19:25:27.735762+00:00 +url = "https://files.pythonhosted.org/packages/ac/c3/e2a2b89f2d3e2179abd6d00ebd70bff6273f37fb3e0cc209f48b39d00cbf/requests-2.34.2.tar.gz" +size = 142856 + +[packages.sdist.hashes] +sha256 = "f288924cae4e29463698d6d60bc6a4da69c89185ad1e0bcc4104f584e960b9ed" + +[[packages.wheels]] +name = "requests-2.34.2-py3-none-any.whl" +upload-time = 2026-05-14 19:25:26.443000+00:00 +url = "https://files.pythonhosted.org/packages/a0/f4/c67b0b3f1b9245e8d266f0f112c500d50e5b4e83cb6f3b71b6528104182a/requests-2.34.2-py3-none-any.whl" +size = 73075 + +[packages.wheels.hashes] +sha256 = "2a0d60c172f83ac6ab31e4554906c0f3b3588d37b5cb939b1c061f4907e278e0" + +[[packages]] +name = "requests-toolbelt" +version = "1.0.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,>=2.7" +dependencies = [ + { name = "requests" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "requests-toolbelt-1.0.0.tar.gz" +upload-time = 2023-05-01 04:11:33.229998+00:00 +url = "https://files.pythonhosted.org/packages/f3/61/d7545dafb7ac2230c70d38d31cbfe4cc64f7144dc41f6e4e4b78ecd9f5bb/requests-toolbelt-1.0.0.tar.gz" +size = 206888 + +[packages.sdist.hashes] +sha256 = "7681a0a3d047012b5bdc0ee37d7f8f07ebe76ab08caeccfc3921ce23c88d5bc6" + +[[packages.wheels]] +name = "requests_toolbelt-1.0.0-py2.py3-none-any.whl" +upload-time = 2023-05-01 04:11:28.427086+00:00 +url = "https://files.pythonhosted.org/packages/3f/51/d4db610ef29373b879047326cbf6fa98b6c1969d6f6dc423279de2b1be2c/requests_toolbelt-1.0.0-py2.py3-none-any.whl" +size = 54481 + +[packages.wheels.hashes] +sha256 = "cccfdd665f0a24fcf4726e690f65639d272bb0637b9b92dfd91a5568ccf6bd06" + +[[packages]] +name = "rfc3986" +version = "2.0.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.7" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "rfc3986-2.0.0.tar.gz" +upload-time = 2022-01-10 00:52:30.832978+00:00 +url = "https://files.pythonhosted.org/packages/85/40/1520d68bfa07ab5a6f065a186815fb6610c86fe957bc065754e47f7b0840/rfc3986-2.0.0.tar.gz" +size = 49026 + +[packages.sdist.hashes] +sha256 = "97aacf9dbd4bfd829baad6e6309fa6573aaf1be3f6fa735c8ab05e46cecb261c" + +[[packages.wheels]] +name = "rfc3986-2.0.0-py2.py3-none-any.whl" +upload-time = 2022-01-10 00:52:29.594625+00:00 +url = "https://files.pythonhosted.org/packages/ff/9a/9afaade874b2fa6c752c36f1548f718b5b83af81ed9b76628329dab81c1b/rfc3986-2.0.0-py2.py3-none-any.whl" +size = 31326 + +[packages.wheels.hashes] +sha256 = "50b1502b60e289cb37883f3dfd34532b8873c7de9f49bb546641ce9cbd256ebd" + +[[packages]] +name = "rich" +version = "15.0.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.9.0" +dependencies = [ + { name = "markdown-it-py" }, + { name = "pygments" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "rich-15.0.0.tar.gz" +upload-time = 2026-04-12 08:24:00.750018+00:00 +url = "https://files.pythonhosted.org/packages/c0/8f/0722ca900cc807c13a6a0c696dacf35430f72e0ec571c4275d2371fca3e9/rich-15.0.0.tar.gz" +size = 230680 + +[packages.sdist.hashes] +sha256 = "edd07a4824c6b40189fb7ac9bc4c52536e9780fbbfbddf6f1e2502c31b068c36" + +[[packages.wheels]] +name = "rich-15.0.0-py3-none-any.whl" +upload-time = 2026-04-12 08:24:02.830783+00:00 +url = "https://files.pythonhosted.org/packages/82/3b/64d4899d73f91ba49a8c18a8ff3f0ea8f1c1d75481760df8c68ef5235bf5/rich-15.0.0-py3-none-any.whl" +size = 310654 + +[packages.wheels.hashes] +sha256 = "33bd4ef74232fb73fe9279a257718407f169c09b78a87ad3d296f548e27de0bb" + +[[packages]] +name = "roman-numerals" +version = "4.1.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "roman_numerals-4.1.0.tar.gz" +upload-time = 2025-12-17 18:25:34.381818+00:00 +url = "https://files.pythonhosted.org/packages/ae/f9/41dc953bbeb056c17d5f7a519f50fdf010bd0553be2d630bc69d1e022703/roman_numerals-4.1.0.tar.gz" +size = 9077 + +[packages.sdist.hashes] +sha256 = "1af8b147eb1405d5839e78aeb93131690495fe9da5c91856cb33ad55a7f1e5b2" + +[[packages.wheels]] +name = "roman_numerals-4.1.0-py3-none-any.whl" +upload-time = 2025-12-17 18:25:33.098993+00:00 +url = "https://files.pythonhosted.org/packages/04/54/6f679c435d28e0a568d8e8a7c0a93a09010818634c3c3907fc98d8983770/roman_numerals-4.1.0-py3-none-any.whl" +size = 7676 + +[packages.wheels.hashes] +sha256 = "647ba99caddc2cc1e55a51e4360689115551bf4476d90e8162cf8c345fe233c7" + +[[packages]] +name = "secretstorage" +version = "3.5.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "cryptography" }, + { name = "jeepney" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "secretstorage-3.5.0.tar.gz" +upload-time = 2025-11-23 19:02:53.191898+00:00 +url = "https://files.pythonhosted.org/packages/1c/03/e834bcd866f2f8a49a85eaff47340affa3bfa391ee9912a952a1faa68c7b/secretstorage-3.5.0.tar.gz" +size = 19884 + +[packages.sdist.hashes] +sha256 = "f04b8e4689cbce351744d5537bf6b1329c6fc68f91fa666f60a380edddcd11be" + +[[packages.wheels]] +name = "secretstorage-3.5.0-py3-none-any.whl" +upload-time = 2025-11-23 19:02:51.545472+00:00 +url = "https://files.pythonhosted.org/packages/b7/46/f5af3402b579fd5e11573ce652019a67074317e18c1935cc0b4ba9b35552/secretstorage-3.5.0-py3-none-any.whl" +size = 15554 + +[packages.wheels.hashes] +sha256 = "0ce65888c0725fcb2c5bc0fdb8e5438eece02c523557ea40ce0703c266248137" + +[[packages]] +name = "setuptools" +version = "84.0.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "setuptools-84.0.0.tar.gz" +upload-time = 2026-08-08 18:27:58.365696+00:00 +url = "https://files.pythonhosted.org/packages/6d/44/f5da03a8ef95d369145c5bb53050e7877c9f3d312e128605fd9504829143/setuptools-84.0.0.tar.gz" +size = 1168449 + +[packages.sdist.hashes] +sha256 = "f4695c21257f0d9b537ec2692c941d02ee143b7cc1276941349a546573b2ef73" + +[[packages.wheels]] +name = "setuptools-84.0.0-py3-none-any.whl" +upload-time = 2026-08-08 18:27:56.719708+00:00 +url = "https://files.pythonhosted.org/packages/95/9c/c510029fc6ef33a6275cd2c5d3cecd6613dfd6aa401d57c54f1c18852ccf/setuptools-84.0.0-py3-none-any.whl" +size = 818216 + +[packages.wheels.hashes] +sha256 = "51a52592b3b99e102b609654876bd65f19f999935166d1352678931132b0c670" + +[[packages]] +name = "setuptools-scm" +version = "10.3.4" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.8" +dependencies = [ + { name = "packaging" }, + { name = "setuptools" }, + { name = "vcs-versioning" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "setuptools_scm-10.3.4.tar.gz" +upload-time = 2026-09-23 19:21:42.950372+00:00 +url = "https://files.pythonhosted.org/packages/85/d8/fc143f88819ccf10ba2388ba86732ee2de193e578234e25a783f6cc14bf7/setuptools_scm-10.3.4.tar.gz" +size = 78410 + +[packages.sdist.hashes] +sha256 = "a69f28bfc245608781205e912faae437c2b2165773afa4e7b979d77447a69dd2" + +[[packages.wheels]] +name = "setuptools_scm-10.3.4-py3-none-any.whl" +upload-time = 2026-09-23 19:21:41.607429+00:00 +url = "https://files.pythonhosted.org/packages/da/f5/54538a1f17ea753c42b0928dc2e62986d463f8c393340b9a1e602f2d4dd9/setuptools_scm-10.3.4-py3-none-any.whl" +size = 33366 + +[packages.wheels.hashes] +sha256 = "82f34c3e3084fc2b57d397200637cc13f2338004052d2fee47baa5f0e902464e" + +[[packages]] +name = "snowballstemmer" +version = "3.1.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.3" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "snowballstemmer-3.1.1.tar.gz" +upload-time = 2026-06-03 00:56:40.194915+00:00 +url = "https://files.pythonhosted.org/packages/43/f8/0a71edf031f03c40db17503cb8ca78a69a171254e568e7db241b0ab57ea1/snowballstemmer-3.1.1.tar.gz" +size = 123314 + +[packages.sdist.hashes] +sha256 = "e07bbc54a0d798fe6010a12398422e62a8bfbba95c394fd0956ef58cb4d3e260" + +[[packages.wheels]] +name = "snowballstemmer-3.1.1-py3-none-any.whl" +upload-time = 2026-06-03 00:56:38.614300+00:00 +url = "https://files.pythonhosted.org/packages/4c/07/2ebca9b11fb9be7340a818d8d6f63feaebb146be2c4afbd6061701d6df6e/snowballstemmer-3.1.1-py3-none-any.whl" +size = 104164 + +[packages.wheels.hashes] +sha256 = "7e207fa178741da09cdee59d3ecec3827ad5f92b1fc5c9ff3755b639f71f5752" + +[[packages]] +name = "soupsieve" +version = "3.0.3" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.11.5" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "soupsieve-3.0.3.tar.gz" +upload-time = 2026-10-12 13:21:17.696815+00:00 +url = "https://files.pythonhosted.org/packages/5e/77/2dcfa996b01702ab8fd0763d84098f6a640d6162a328f1c04c2697579a1a/soupsieve-3.0.3.tar.gz" +size = 115923 + +[packages.sdist.hashes] +sha256 = "7dcf6022eed0399eb9934a75e020148f7a2024c37b7dfcd3cf2c5505d69c364e" + +[[packages.wheels]] +name = "soupsieve-3.0.3-py3-none-any.whl" +upload-time = 2026-10-12 13:21:16.474827+00:00 +url = "https://files.pythonhosted.org/packages/49/ca/f639c80449997b88aba7bc9705d25dd76cc0844f45f187862fd8f8bb18fa/soupsieve-3.0.3-py3-none-any.whl" +size = 41705 + +[packages.wheels.hashes] +sha256 = "fa30e3ba4809cb81ce1f3209f2fbe3e779fc445f0439bc147a0d7c4601743f21" + +[[packages]] +name = "sphinx" +version = "9.1.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.12" +dependencies = [ + { name = "alabaster" }, + { name = "babel" }, + { name = "docutils" }, + { name = "imagesize" }, + { name = "jinja2" }, + { name = "packaging" }, + { name = "pygments" }, + { name = "requests" }, + { name = "roman-numerals" }, + { name = "snowballstemmer" }, + { name = "sphinxcontrib-applehelp" }, + { name = "sphinxcontrib-devhelp" }, + { name = "sphinxcontrib-htmlhelp" }, + { name = "sphinxcontrib-jsmath" }, + { name = "sphinxcontrib-qthelp" }, + { name = "sphinxcontrib-serializinghtml" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx-9.1.0.tar.gz" +upload-time = 2025-12-31 15:09:27.646696+00:00 +url = "https://files.pythonhosted.org/packages/cd/bd/f08eb0f4eed5c83f1ba2a3bd18f7745a2b1525fad70660a1c00224ec468a/sphinx-9.1.0.tar.gz" +size = 8718324 + +[packages.sdist.hashes] +sha256 = "7741722357dd75f8190766926071fed3bdc211c74dd2d7d4df5404da95930ddb" + +[[packages.wheels]] +name = "sphinx-9.1.0-py3-none-any.whl" +upload-time = 2025-12-31 15:09:25.561651+00:00 +url = "https://files.pythonhosted.org/packages/73/f7/b1884cb3188ab181fc81fa00c266699dab600f927a964df02ec3d5d1916a/sphinx-9.1.0-py3-none-any.whl" +size = 3921742 + +[packages.wheels.hashes] +sha256 = "c84fdd4e782504495fe4f2c0b3413d6c2bf388589bb352d439b2a3bb99991978" + +[[packages]] +name = "sphinx-autodoc-typehints" +version = "3.17.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.12" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_autodoc_typehints-3.17.2.tar.gz" +upload-time = 2026-10-17 18:30:30.923136+00:00 +url = "https://files.pythonhosted.org/packages/9c/fa/c967fd665cc102c90338a90292aba336f852ee6f9b3477ffe4da565edb11/sphinx_autodoc_typehints-3.17.2.tar.gz" +size = 570767 + +[packages.sdist.hashes] +sha256 = "de41ed4001f4818bb6d37c22fd10ee44a93e6c8e945c6c7e3984e28a9df87d1c" + +[[packages.wheels]] +name = "sphinx_autodoc_typehints-3.17.2-py3-none-any.whl" +upload-time = 2026-10-17 18:30:28.728186+00:00 +url = "https://files.pythonhosted.org/packages/78/d4/8fc500ff2fafe8a6e1847abd8b1072494dc1a5f136f8e890e973db7de4eb/sphinx_autodoc_typehints-3.17.2-py3-none-any.whl" +size = 140285 + +[packages.wheels.hashes] +sha256 = "b0ad1f96503d69b63c2a1c043f12e2a727c9549e6503d4adbf2125dbf5ff50ed" + +[[packages]] +name = "sphinx-basic-ng" +version = "1.0.0b2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_basic_ng-1.0.0b2.tar.gz" +upload-time = 2023-07-08 18:40:54.166146+00:00 +url = "https://files.pythonhosted.org/packages/98/0b/a866924ded68efec7a1759587a4e478aec7559d8165fac8b2ad1c0e774d6/sphinx_basic_ng-1.0.0b2.tar.gz" +size = 20736 + +[packages.sdist.hashes] +sha256 = "9ec55a47c90c8c002b5960c57492ec3021f5193cb26cebc2dc4ea226848651c9" + +[[packages.wheels]] +name = "sphinx_basic_ng-1.0.0b2-py3-none-any.whl" +upload-time = 2023-07-08 18:40:52.659879+00:00 +url = "https://files.pythonhosted.org/packages/3c/dd/018ce05c532a22007ac58d4f45232514cd9d6dd0ee1dc374e309db830983/sphinx_basic_ng-1.0.0b2-py3-none-any.whl" +size = 22496 + +[packages.wheels.hashes] +sha256 = "eb09aedbabfb650607e9b4b68c9d240b90b1e1be221d6ad71d61c52e29f7932b" + +[[packages]] +name = "sphinx-copybutton" +version = "0.5.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx-copybutton-0.5.2.tar.gz" +upload-time = 2023-04-14 08:10:22.998763+00:00 +url = "https://files.pythonhosted.org/packages/fc/2b/a964715e7f5295f77509e59309959f4125122d648f86b4fe7d70ca1d882c/sphinx-copybutton-0.5.2.tar.gz" +size = 23039 + +[packages.sdist.hashes] +sha256 = "4cf17c82fb9646d1bc9ca92ac280813a3b605d8c421225fd9913154103ee1fbd" + +[[packages.wheels]] +name = "sphinx_copybutton-0.5.2-py3-none-any.whl" +upload-time = 2023-04-14 08:10:20.844249+00:00 +url = "https://files.pythonhosted.org/packages/9e/48/1ea60e74949eecb12cdd6ac43987f9fd331156388dcc2319b45e2ebb81bf/sphinx_copybutton-0.5.2-py3-none-any.whl" +size = 13343 + +[packages.wheels.hashes] +sha256 = "fb543fd386d917746c9a2c50360c7905b605726b9355cd26e9974857afeae06e" + +[[packages]] +name = "sphinx-design" +version = "0.7.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.11" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_design-0.7.0.tar.gz" +upload-time = 2026-01-19 13:12:53.297780+00:00 +url = "https://files.pythonhosted.org/packages/13/7b/804f311da4663a4aecc6cf7abd83443f3d4ded970826d0c958edc77d4527/sphinx_design-0.7.0.tar.gz" +size = 2203582 + +[packages.sdist.hashes] +sha256 = "d2a3f5b19c24b916adb52f97c5f00efab4009ca337812001109084a740ec9b7a" + +[[packages.wheels]] +name = "sphinx_design-0.7.0-py3-none-any.whl" +upload-time = 2026-01-19 13:12:51.077508+00:00 +url = "https://files.pythonhosted.org/packages/30/cf/45dd359f6ca0c3762ce0490f681da242f0530c49c81050c035c016bfdd3a/sphinx_design-0.7.0-py3-none-any.whl" +size = 2220350 + +[packages.wheels.hashes] +sha256 = "f82bf179951d58f55dca78ab3706aeafa496b741a91b1911d371441127d64282" + +[[packages]] +name = "sphinx-last-updated-by-git" +version = "0.3.8" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_last_updated_by_git-0.3.8.tar.gz" +upload-time = 2024-08-11 07:15:54.601652+00:00 +url = "https://files.pythonhosted.org/packages/03/fd/de1685b6dab173dff31da24e0d3b29f02873fc24a1cdbb7678721ddc8581/sphinx_last_updated_by_git-0.3.8.tar.gz" +size = 10785 + +[packages.sdist.hashes] +sha256 = "c145011f4609d841805b69a9300099fc02fed8f5bb9e5bcef77d97aea97b7761" + +[[packages.wheels]] +name = "sphinx_last_updated_by_git-0.3.8-py3-none-any.whl" +upload-time = 2024-08-11 07:15:53.244461+00:00 +url = "https://files.pythonhosted.org/packages/e1/fb/e496f16fa11fbe2dbdd0b5e306ede153dfed050aae4766fc89d500720dc7/sphinx_last_updated_by_git-0.3.8-py3-none-any.whl" +size = 8580 + +[packages.wheels.hashes] +sha256 = "6382c8285ac1f222483a58569b78c0371af5e55f7fbf9c01e5e8a72d6fdfa499" + +[[packages]] +name = "sphinx-llm" +version = "1.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "sphinx" }, + { name = "sphinx-markdown-builder" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_llm-1.0.0.tar.gz" +upload-time = 2026-08-14 07:48:29.578550+00:00 +url = "https://files.pythonhosted.org/packages/33/58/6b1802820a17e7a128b45046d735f934af00f4290704b647b126213bdeb4/sphinx_llm-1.0.0.tar.gz" +size = 381976 + +[packages.sdist.hashes] +sha256 = "1cc8284343a0100caa3110010da5933cdad8da37d2b9dda0e2a7d503b8da6b1c" + +[[packages.wheels]] +name = "sphinx_llm-1.0.0-py3-none-any.whl" +upload-time = 2026-08-14 07:48:28.161181+00:00 +url = "https://files.pythonhosted.org/packages/af/5b/2a338974998bc0fe563635625abdb16a000ee06a63101b361c834cd56ccb/sphinx_llm-1.0.0-py3-none-any.whl" +size = 60282 + +[packages.wheels.hashes] +sha256 = "8d45dbe5f9caffb4d78589c35d15fc8399dd41fc5b445ee4292ff83969754e75" + +[[packages]] +name = "sphinx-markdown-builder" +version = "0.6.11" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.7" +dependencies = [ + { name = "docutils" }, + { name = "sphinx" }, + { name = "tabulate" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_markdown_builder-0.6.11.tar.gz" +upload-time = 2026-08-16 06:51:38.158799+00:00 +url = "https://files.pythonhosted.org/packages/ad/13/102d7134743120db25e636ffb57a30818e95a416583dca83aadac9c5dd87/sphinx_markdown_builder-0.6.11.tar.gz" +size = 24020 + +[packages.sdist.hashes] +sha256 = "ba3bf33e0e42ff30ae686ac73957a95e6d045790dcfbaca012dd8ae01794e577" + +[[packages.wheels]] +name = "sphinx_markdown_builder-0.6.11-py3-none-any.whl" +upload-time = 2026-08-16 06:51:36.810420+00:00 +url = "https://files.pythonhosted.org/packages/c9/71/06b415631c2e494c80546073b46013d1715dceb3abe30bd63b34b4e7d9ca/sphinx_markdown_builder-0.6.11-py3-none-any.whl" +size = 18088 + +[packages.wheels.hashes] +sha256 = "acfb94d6ee66c7a47da0ca0420578fa16f115812af25b8fd21755d5909aacf51" + +[[packages]] +name = "sphinx-sitemap" +version = "2.9.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +dependencies = [ + { name = "sphinx-last-updated-by-git" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinx_sitemap-2.9.0.tar.gz" +upload-time = 2025-10-06 00:24:00.036537+00:00 +url = "https://files.pythonhosted.org/packages/61/17/56fe0f65e3567f829b2b4153a622be1d4b222b781e0d90d7db5a7738f30f/sphinx_sitemap-2.9.0.tar.gz" +size = 6978 + +[packages.sdist.hashes] +sha256 = "70f97bcdf444e3d68e118355cf82a1f54c4d3c03d651cd17fe87398b26e25e21" + +[[packages.wheels]] +name = "sphinx_sitemap-2.9.0-py3-none-any.whl" +upload-time = 2025-10-06 00:23:58.778831+00:00 +url = "https://files.pythonhosted.org/packages/e4/94/3c57e8b1985e755c48972e2ecd59526d4bf0b52a1fe805bc52a8e98cb92d/sphinx_sitemap-2.9.0-py3-none-any.whl" +size = 6218 + +[packages.wheels.hashes] +sha256 = "f1f1d3a9ad012ba17a7ef0b560d303bff2d0db26647567d6e810bcc754466664" + +[[packages]] +name = "sphinxcontrib-applehelp" +version = "2.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_applehelp-2.0.0.tar.gz" +upload-time = 2024-07-29 01:09:00.465812+00:00 +url = "https://files.pythonhosted.org/packages/ba/6e/b837e84a1a704953c62ef8776d45c3e8d759876b4a84fe14eba2859106fe/sphinxcontrib_applehelp-2.0.0.tar.gz" +size = 20053 + +[packages.sdist.hashes] +sha256 = "2f29ef331735ce958efa4734873f084941970894c6090408b079c61b2e1c06d1" + +[[packages.wheels]] +name = "sphinxcontrib_applehelp-2.0.0-py3-none-any.whl" +upload-time = 2024-07-29 01:08:58.990722+00:00 +url = "https://files.pythonhosted.org/packages/5d/85/9ebeae2f76e9e77b952f4b274c27238156eae7979c5421fba91a28f4970d/sphinxcontrib_applehelp-2.0.0-py3-none-any.whl" +size = 119300 + +[packages.wheels.hashes] +sha256 = "4cd3f0ec4ac5dd9c17ec65e9ab272c9b867ea77425228e68ecf08d6b28ddbdb5" + +[[packages]] +name = "sphinxcontrib-devhelp" +version = "2.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_devhelp-2.0.0.tar.gz" +upload-time = 2024-07-29 01:09:23.417467+00:00 +url = "https://files.pythonhosted.org/packages/f6/d2/5beee64d3e4e747f316bae86b55943f51e82bb86ecd325883ef65741e7da/sphinxcontrib_devhelp-2.0.0.tar.gz" +size = 12967 + +[packages.sdist.hashes] +sha256 = "411f5d96d445d1d73bb5d52133377b4248ec79db5c793ce7dbe59e074b4dd1ad" + +[[packages.wheels]] +name = "sphinxcontrib_devhelp-2.0.0-py3-none-any.whl" +upload-time = 2024-07-29 01:09:21.945229+00:00 +url = "https://files.pythonhosted.org/packages/35/7a/987e583882f985fe4d7323774889ec58049171828b58c2217e7f79cdf44e/sphinxcontrib_devhelp-2.0.0-py3-none-any.whl" +size = 82530 + +[packages.wheels.hashes] +sha256 = "aefb8b83854e4b0998877524d1029fd3e6879210422ee3780459e28a1f03a8a2" + +[[packages]] +name = "sphinxcontrib-htmlhelp" +version = "2.1.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_htmlhelp-2.1.0.tar.gz" +upload-time = 2024-07-29 01:09:37.889318+00:00 +url = "https://files.pythonhosted.org/packages/43/93/983afd9aa001e5201eab16b5a444ed5b9b0a7a010541e0ddfbbfd0b2470c/sphinxcontrib_htmlhelp-2.1.0.tar.gz" +size = 22617 + +[packages.sdist.hashes] +sha256 = "c9e2916ace8aad64cc13a0d233ee22317f2b9025b9cf3295249fa985cc7082e9" + +[[packages.wheels]] +name = "sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl" +upload-time = 2024-07-29 01:09:36.407072+00:00 +url = "https://files.pythonhosted.org/packages/0a/7b/18a8c0bcec9182c05a0b3ec2a776bba4ead82750a55ff798e8d406dae604/sphinxcontrib_htmlhelp-2.1.0-py3-none-any.whl" +size = 98705 + +[packages.wheels.hashes] +sha256 = "166759820b47002d22914d64a075ce08f4c46818e17cfc9470a9786b759b19f8" + +[[packages]] +name = "sphinxcontrib-jsmath" +version = "1.0.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.5" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib-jsmath-1.0.1.tar.gz" +upload-time = 2019-01-21 16:10:16.347697+00:00 +url = "https://files.pythonhosted.org/packages/b2/e8/9ed3830aeed71f17c026a07a5097edcf44b692850ef215b161b8ad875729/sphinxcontrib-jsmath-1.0.1.tar.gz" +size = 5787 + +[packages.sdist.hashes] +sha256 = "a9925e4a4587247ed2191a22df5f6970656cb8ca2bd6284309578f2153e0c4b8" + +[[packages.wheels]] +name = "sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl" +upload-time = 2019-01-21 16:10:14.333769+00:00 +url = "https://files.pythonhosted.org/packages/c2/42/4c8646762ee83602e3fb3fbe774c2fac12f317deb0b5dbeeedd2d3ba4b77/sphinxcontrib_jsmath-1.0.1-py2.py3-none-any.whl" +size = 5071 + +[packages.wheels.hashes] +sha256 = "2ec2eaebfb78f3f2078e73666b1415417a116cc848b72e5172e596c871103178" + +[[packages]] +name = "sphinxcontrib-mermaid" +version = "2.1.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "jinja2" }, + { name = "pyyaml" }, + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_mermaid-2.1.1.tar.gz" +upload-time = 2026-09-01 16:10:23.671939+00:00 +url = "https://files.pythonhosted.org/packages/8c/87/06537dff20aa57df2d0f2afa87edff4afa85dec6f57f03f7acc24f83ff88/sphinxcontrib_mermaid-2.1.1.tar.gz" +size = 22353 + +[packages.sdist.hashes] +sha256 = "f8d7f1b2f0ad69b7ebdd5cbf532fb4ee107893b5373bc2d0e9634089c0b2cfee" + +[[packages.wheels]] +name = "sphinxcontrib_mermaid-2.1.1-py3-none-any.whl" +upload-time = 2026-09-01 16:10:22.377054+00:00 +url = "https://files.pythonhosted.org/packages/50/6a/5bf2222b8084c7a7bc3ec23d470c91e3e03e82e4ce0bbacaa61f456ce7c1/sphinxcontrib_mermaid-2.1.1-py3-none-any.whl" +size = 16368 + +[packages.wheels.hashes] +sha256 = "3b9ac1a8e0b5154dec3c0acf9b5c54dd9ba58540e416f20858c300814c25648f" + +[[packages]] +name = "sphinxcontrib-qthelp" +version = "2.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_qthelp-2.0.0.tar.gz" +upload-time = 2024-07-29 01:09:56.435212+00:00 +url = "https://files.pythonhosted.org/packages/68/bc/9104308fc285eb3e0b31b67688235db556cd5b0ef31d96f30e45f2e51cae/sphinxcontrib_qthelp-2.0.0.tar.gz" +size = 17165 + +[packages.sdist.hashes] +sha256 = "4fe7d0ac8fc171045be623aba3e2a8f613f8682731f9153bb2e40ece16b9bbab" + +[[packages.wheels]] +name = "sphinxcontrib_qthelp-2.0.0-py3-none-any.whl" +upload-time = 2024-07-29 01:09:54.885300+00:00 +url = "https://files.pythonhosted.org/packages/27/83/859ecdd180cacc13b1f7e857abf8582a64552ea7a061057a6c716e790fce/sphinxcontrib_qthelp-2.0.0-py3-none-any.whl" +size = 88743 + +[packages.wheels.hashes] +sha256 = "b18a828cdba941ccd6ee8445dbe72ffa3ef8cbe7505d8cd1fa0d42d3f2d5f3eb" + +[[packages]] +name = "sphinxcontrib-serializinghtml" +version = "2.0.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_serializinghtml-2.0.0.tar.gz" +upload-time = 2024-07-29 01:10:09.332393+00:00 +url = "https://files.pythonhosted.org/packages/3b/44/6716b257b0aa6bfd51a1b31665d1c205fb12cb5ad56de752dfa15657de2f/sphinxcontrib_serializinghtml-2.0.0.tar.gz" +size = 16080 + +[packages.sdist.hashes] +sha256 = "e9d912827f872c029017a53f0ef2180b327c3f7fd23c87229f7a8e8b70031d4d" + +[[packages.wheels]] +name = "sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl" +upload-time = 2024-07-29 01:10:08.203690+00:00 +url = "https://files.pythonhosted.org/packages/52/a7/d2782e4e3f77c8450f727ba74a8f12756d5ba823d81b941f1b04da9d033a/sphinxcontrib_serializinghtml-2.0.0-py3-none-any.whl" +size = 92072 + +[packages.wheels.hashes] +sha256 = "6e2cb0eef194e10c27ec0023bfeb25badbbb5868244cf5bc5bdc04e4464bf331" + +[[packages]] +name = "sphinxcontrib-towncrier" +version = "0.5.0a0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "sphinx" }, + { name = "towncrier" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxcontrib_towncrier-0.5.0a0.tar.gz" +upload-time = 2025-02-28 01:59:16.894775+00:00 +url = "https://files.pythonhosted.org/packages/21/fe/72ed57093e28af10595c50839b183c5fdf0952482e9ef0ca6eb90eb85c5d/sphinxcontrib_towncrier-0.5.0a0.tar.gz" +size = 62453 + +[packages.sdist.hashes] +sha256 = "294e69df6e275e7a86df7ea6a927cc7c28c2c370a884cd5c45de6ec989858f27" + +[[packages.wheels]] +name = "sphinxcontrib_towncrier-0.5.0a0-py3-none-any.whl" +upload-time = 2025-02-28 01:59:15.178594+00:00 +url = "https://files.pythonhosted.org/packages/ac/5c/f7e39f243636a5e1894f2f5a72579977bf3968922afdb75175ee45062066/sphinxcontrib_towncrier-0.5.0a0-py3-none-any.whl" +size = 12609 + +[packages.wheels.hashes] +sha256 = "11d130c3ad5e4649821d543c4ea7ab64bbe78df4d859ef94f4298e7845dc0f59" + +[[packages]] +name = "sphinxext-opengraph" +version = "0.13.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "sphinx" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "sphinxext_opengraph-0.13.0.tar.gz" +upload-time = 2025-08-29 12:20:31.066405+00:00 +url = "https://files.pythonhosted.org/packages/f6/c0/eb6838e3bae624ce6c8b90b245d17e84252863150e95efdb88f92c8aa3fb/sphinxext_opengraph-0.13.0.tar.gz" +size = 1026875 + +[packages.sdist.hashes] +sha256 = "103335d08567ad8468faf1425f575e3b698e9621f9323949a6c8b96d9793e80b" + +[[packages.wheels]] +name = "sphinxext_opengraph-0.13.0-py3-none-any.whl" +upload-time = 2025-08-29 12:20:29.072834+00:00 +url = "https://files.pythonhosted.org/packages/bf/a4/66c1fd4f8fab88faf71cee04a945f9806ba0fef753f2cfc8be6353f64508/sphinxext_opengraph-0.13.0-py3-none-any.whl" +size = 1004152 + +[packages.wheels.hashes] +sha256 = "936c07828edc9ad9a7b07908b29596dc84ed0b3ceaa77acdf51282d232d4d80e" + +[[packages]] +name = "tabulate" +version = "0.10.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "tabulate-0.10.0.tar.gz" +upload-time = 2026-03-04 18:55:34.402969+00:00 +url = "https://files.pythonhosted.org/packages/46/58/8c37dea7bbf769b20d58e7ace7e5edfe65b849442b00ffcdd56be88697c6/tabulate-0.10.0.tar.gz" +size = 91754 + +[packages.sdist.hashes] +sha256 = "e2cfde8f79420f6deeffdeda9aaec3b6bc5abce947655d17ac662b126e48a60d" + +[[packages.wheels]] +name = "tabulate-0.10.0-py3-none-any.whl" +upload-time = 2026-03-04 18:55:31.284751+00:00 +url = "https://files.pythonhosted.org/packages/99/55/db07de81b5c630da5cbf5c7df646580ca26dfaefa593667fc6f2fe016d2e/tabulate-0.10.0-py3-none-any.whl" +size = 39814 + +[packages.wheels.hashes] +sha256 = "f0b0622e567335c8fabaaa659f1b33bcb6ddfe2e496071b743aa113f8774f2d3" + +[[packages]] +name = "tomlkit" +version = "0.15.2" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "tomlkit-0.15.2.tar.gz" +upload-time = 2026-10-16 04:07:08.166827+00:00 +url = "https://files.pythonhosted.org/packages/08/72/fc01563df95c189a9f65850096bdc205bc2fe37da6c740cd64afaf18d07e/tomlkit-0.15.2.tar.gz" +size = 190522 + +[packages.sdist.hashes] +sha256 = "83e32755ba1d20d9340bd069ee97e9f6232ba2346b63ffcba425de01f7e327a6" + +[[packages.wheels]] +name = "tomlkit-0.15.2-py3-none-any.whl" +upload-time = 2026-10-16 04:07:09.216014+00:00 +url = "https://files.pythonhosted.org/packages/da/46/7d84138a60a8bd796825b2d38ebe92d0d16501ca57d501b7c5d677401bbc/tomlkit-0.15.2-py3-none-any.whl" +size = 52225 + +[packages.wheels.hashes] +sha256 = "05562412163a3037b94497385fb7f9204c637bc605af7a48199e41cf2272f437" + +[[packages]] +name = "towncrier" +version = "26.9.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "click" }, + { name = "jinja2" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "towncrier-26.9.0.tar.gz" +upload-time = 2026-09-04 12:57:25.341701+00:00 +url = "https://files.pythonhosted.org/packages/92/d4/e85ce614bf45b1a7fe13b82cc687819c2eaac5a1dd94b84834322095fd98/towncrier-26.9.0.tar.gz" +size = 79338 + +[packages.sdist.hashes] +sha256 = "ace9031631c718cc0709107b8755e6e31350eb8acdc877af43df3177addb9a55" + +[[packages.wheels]] +name = "towncrier-26.9.0-py3-none-any.whl" +upload-time = 2026-09-04 12:57:23.986160+00:00 +url = "https://files.pythonhosted.org/packages/82/88/f9340b545dafa64de053798e760515a2736fbb60092cf9aa6b146ccf3ede/towncrier-26.9.0-py3-none-any.whl" +size = 67030 + +[packages.wheels.hashes] +sha256 = "ae4d223e6aadaff98d29b7f09e58d9c9ccf4cd3b455a2d2e0486d432cd8bf660" + +[[packages]] +name = "trove-classifiers" +version = "2026.9.21.13" +marker = "\"build\" in dependency_groups" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "trove_classifiers-2026.9.21.13.tar.gz" +upload-time = 2026-09-21 13:29:07.301512+00:00 +url = "https://files.pythonhosted.org/packages/bf/93/af436dfaa845cab5d96f0adbc1e4f3730532d37fa249e4eb796fb1d7fc82/trove_classifiers-2026.9.21.13.tar.gz" +size = 17085 + +[packages.sdist.hashes] +sha256 = "0a9ebc8d4e2f3e8a22848c5258033035bec17a3012ac3fea16dbaa764489eb71" + +[[packages.wheels]] +name = "trove_classifiers-2026.9.21.13-py3-none-any.whl" +upload-time = 2026-09-21 13:29:06.123578+00:00 +url = "https://files.pythonhosted.org/packages/30/81/0da8afb52a71d0a4f2bd3152357b1a441e393b286374802b9d3addab4ab5/trove_classifiers-2026.9.21.13-py3-none-any.whl" +size = 14232 + +[packages.wheels.hashes] +sha256 = "8b1ff4f9c191b1040b71c37f1e445ab99732911e3cd91de52838453a854d7a17" + +[[packages]] +name = "twine" +version = "7.0.0" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "id" }, + { name = "keyring" }, + { name = "packaging" }, + { name = "readme-renderer" }, + { name = "requests" }, + { name = "requests-toolbelt" }, + { name = "rfc3986" }, + { name = "rich" }, + { name = "urllib3" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "twine-7.0.0.tar.gz" +upload-time = 2026-07-27 15:59:00.825945+00:00 +url = "https://files.pythonhosted.org/packages/92/3c/58f808a359700f39a967dffede33efeac809262c03303fa3eec6afff8f49/twine-7.0.0.tar.gz" +size = 215032 + +[packages.sdist.hashes] +sha256 = "85cdb29c518efef867360ae4acd4b0dfd61c8654a22fca08e6f8539f05022177" + +[[packages.wheels]] +name = "twine-7.0.0-py3-none-any.whl" +upload-time = 2026-07-27 15:58:59.260418+00:00 +url = "https://files.pythonhosted.org/packages/96/08/ddcdc06225eaad6de0e48e1002b06d919dbde20582d0662c7af51308e5d6/twine-7.0.0-py3-none-any.whl" +size = 43204 + +[packages.wheels.hashes] +sha256 = "b854164df26db268af05f49aa5c0344b10e27a494343ff05b1e0bad3b135f5a7" + +[[packages]] +name = "ty" +version = "0.0.89" +marker = "\"dev\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "ty-0.0.89.tar.gz" +upload-time = 2026-10-16 10:35:05.249809+00:00 +url = "https://files.pythonhosted.org/packages/67/ea/dfb9bdbc168c50a568809466596751afa0c7da60da03b8c12906d1decde4/ty-0.0.89.tar.gz" +size = 7978241 + +[packages.sdist.hashes] +sha256 = "bc1027b1ea95cca25c2a3a0b41433c809cf4b86a384d2b2434eba4bcd34548d4" + +[[packages.wheels]] +name = "ty-0.0.89-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-10-16 10:34:44.063367+00:00 +url = "https://files.pythonhosted.org/packages/3e/61/da22c714fd4f4dff642d60fb0d8bf8da1985d126f21cc89237f8bf707c92/ty-0.0.89-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 14510395 + +[packages.wheels.hashes] +sha256 = "95a410f10b26cc3861757b626727db9d979deba7d2a3ab59f964fac8f0514fdc" + +[[packages]] +name = "typing-extensions" +version = "4.16.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "typing_extensions-4.16.0.tar.gz" +upload-time = 2026-07-02 08:40:05.920538+00:00 +url = "https://files.pythonhosted.org/packages/f6/cc/6253133b5bb138fc3306cebfbda2c520f545d36b5be2c7255cc528bb45d6/typing_extensions-4.16.0.tar.gz" +size = 113555 + +[packages.sdist.hashes] +sha256 = "dc983d19a509c94dba722ee6abd33940f7c05a89e243c47e907eb4db6f1a43e5" + +[[packages.wheels]] +name = "typing_extensions-4.16.0-py3-none-any.whl" +upload-time = 2026-07-02 08:40:04.659120+00:00 +url = "https://files.pythonhosted.org/packages/49/d3/b8441a820a491ddfc024b0b0cf0393375b75ea13866d9c66727e54c2fc80/typing_extensions-4.16.0-py3-none-any.whl" +size = 45571 + +[packages.wheels.hashes] +sha256 = "481caa481374e813c1b176ada14e97f1f67a4539ce9cfeb3f350d78d6370c2e8" + +[[packages]] +name = "typing-inspection" +version = "0.4.4" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.10" +dependencies = [ + { name = "typing-extensions" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "typing_inspection-0.4.4.tar.gz" +upload-time = 2026-08-12 12:37:25.997329+00:00 +url = "https://files.pythonhosted.org/packages/a3/26/b09b8010994eccc3c09092e6b34058f36a460eea2d4c3e8b910c695975a0/typing_inspection-0.4.4.tar.gz" +size = 76928 + +[packages.sdist.hashes] +sha256 = "547274fa6b0a561ccf549cc9524b999a578e737d015d8709d021f9d0d13bea47" + +[[packages.wheels]] +name = "typing_inspection-0.4.4-py3-none-any.whl" +upload-time = 2026-08-12 12:37:24.648475+00:00 +url = "https://files.pythonhosted.org/packages/67/81/4add07e5172b7ac40d8ed5ff580409a7801a4fe26d529bdd915401dabfbe/typing_inspection-0.4.4-py3-none-any.whl" +size = 14750 + +[packages.wheels.hashes] +sha256 = "65b8397ba37ccbce054456aaccddfc91e6e3083c92824df348d96ca832f3f147" + +[[packages]] +name = "urllib3" +version = "2.8.0" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"docs-core\" in dependency_groups or \"pkg-meta\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.10" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "urllib3-2.8.0.tar.gz" +upload-time = 2026-09-15 19:29:36.253420+00:00 +url = "https://files.pythonhosted.org/packages/e3/05/b17359e1cefb4f909b5e40b1b90a496d987258916dbbf88e842c729f510e/urllib3-2.8.0.tar.gz" +size = 458972 + +[packages.sdist.hashes] +sha256 = "63bf2ead4c879426ebf22ef2a781eeb4aa3b4ae798a0435506f8687fd5bb9b63" + +[[packages.wheels]] +name = "urllib3-2.8.0-py3-none-any.whl" +upload-time = 2026-09-15 19:29:34.577402+00:00 +url = "https://files.pythonhosted.org/packages/92/9d/c4e665119135114480843e7ab388fa94d8480650450e6f8e26b70d323a4c/urllib3-2.8.0-py3-none-any.whl" +size = 135717 + +[packages.wheels.hashes] +sha256 = "0cf3cae568d36aa9576b28dfb35f11328f1cb974ca7647d9475ebb86c75ac6e3" + +[[packages]] +name = "uv" +version = "0.13.1" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"fix\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "uv-0.13.1.tar.gz" +upload-time = 2026-10-14 05:13:35.353145+00:00 +url = "https://files.pythonhosted.org/packages/ef/10/81f499de381ac81e09961e1c19255c5cf49563ac418464def4190b6c7400/uv-0.13.1.tar.gz" +size = 7434239 + +[packages.sdist.hashes] +sha256 = "6df50a86b09be66a413f8f1b16258d585d4dd1cbff591077ae1e6f65c26de2eb" + +[[packages.wheels]] +name = "uv-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +upload-time = 2026-10-14 05:13:13.069021+00:00 +url = "https://files.pythonhosted.org/packages/14/0b/6602a613533602e7a083e908c4375f9b0e78a94ba2e21c29b21c41a0a611/uv-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl" +size = 17279385 + +[packages.wheels.hashes] +sha256 = "696dcf6d807d85da978f4db8472da81dccc1254b18b52cbd1367c4d923c421e0" + +[[packages]] +name = "vcs-versioning" +version = "2.6.0" +marker = "\"build\" in dependency_groups" +requires-python = ">=3.8" +dependencies = [ + { name = "packaging" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "vcs_versioning-2.6.0.tar.gz" +upload-time = 2026-10-06 22:21:55.024903+00:00 +url = "https://files.pythonhosted.org/packages/ad/e7/2a691db7d076b75d099fdba1a14cd966931f2aeb591e77f6d22f15097326/vcs_versioning-2.6.0.tar.gz" +size = 166800 + +[packages.sdist.hashes] +sha256 = "22e9159288e2d8bca2fa6f6c31c34c9c66aec157f60e9e526f5d160d2516d60f" + +[[packages.wheels]] +name = "vcs_versioning-2.6.0-py3-none-any.whl" +upload-time = 2026-10-06 22:21:53.267565+00:00 +url = "https://files.pythonhosted.org/packages/73/1d/ad4064bf12f4503bf61e65d74c93c523672776d25ee0a06aaf42ae09ef3f/vcs_versioning-2.6.0-py3-none-any.whl" +size = 123154 + +[packages.wheels.hashes] +sha256 = "f8bebd1302ebc12e67ceb30fc7dd698ec969414b6fa43b30c3f14ac9b1e72c41" + +[[packages]] +name = "virtualenv" +version = "21.14.11" +marker = "\"dev\" in dependency_groups or \"fix\" in dependency_groups" +requires-python = ">=3.9" +dependencies = [ + { name = "distlib" }, + { name = "filelock" }, + { name = "packaging" }, + { name = "platformdirs" }, + { name = "python-discovery" }, +] +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "virtualenv-21.14.11.tar.gz" +upload-time = 2026-10-18 07:06:34.716606+00:00 +url = "https://files.pythonhosted.org/packages/7f/be/4d1d59d309db76b5808fcfd78bd5996f4e7241366691c38fc331a3136398/virtualenv-21.14.11.tar.gz" +size = 5503091 + +[packages.sdist.hashes] +sha256 = "593052d8477ea8c55a842387ce111bd08c72618f0c1133c302cafe335e570a57" + +[[packages.wheels]] +name = "virtualenv-21.14.11-py3-none-any.whl" +upload-time = 2026-10-18 07:06:32.719110+00:00 +url = "https://files.pythonhosted.org/packages/ce/6b/d85da8982b41190eafcb9df91dff9d83fc6989e98af4b5be4c8f85510c95/virtualenv-21.14.11-py3-none-any.whl" +size = 5495268 + +[packages.wheels.hashes] +sha256 = "b319f8590a84e5de5f8f2c803ecd2237e9bc0ffa7c1e875e3169c107cecb7454" + +[[packages]] +name = "wcwidth" +version = "0.9.2" +marker = "\"dev\" in dependency_groups or \"docs\" in dependency_groups or \"release\" in dependency_groups or \"release-news\" in dependency_groups or \"release-notes\" in dependency_groups or \"release-prepare\" in dependency_groups or \"type\" in dependency_groups" +requires-python = ">=3.9" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "wcwidth-0.9.2.tar.gz" +upload-time = 2026-10-05 00:24:05.521972+00:00 +url = "https://files.pythonhosted.org/packages/f0/b4/7830542634bb2d3e62aa3b586a72d5b3b6c91c3168929e7000ef3fed041d/wcwidth-0.9.2.tar.gz" +size = 955039 + +[packages.sdist.hashes] +sha256 = "ae0ef90b90f6af38b54f1fe6d58662ec33b3cb4b8391958a62416d654231727b" + +[[packages.wheels]] +name = "wcwidth-0.9.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +upload-time = 2026-10-05 00:23:40.175985+00:00 +url = "https://files.pythonhosted.org/packages/db/6c/f940133c71427c208575910e981942bd78c98b1f7cd0d1425ca4b7457c04/wcwidth-0.9.2-cp310-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl" +size = 769763 + +[packages.wheels.hashes] +sha256 = "751bef0ab404b6a1dc028b56b4b85d46486be1c55833f80da533e42dc691f389" + +[[packages.wheels]] +name = "wcwidth-0.9.2-py3-none-any.whl" +upload-time = 2026-10-05 00:23:21.097514+00:00 +url = "https://files.pythonhosted.org/packages/9c/b4/0bfa065af506540d9d558e3e5548cff00bc1f9b24e6e2a8512498e8628de/wcwidth-0.9.2-py3-none-any.whl" +size = 301667 + +[packages.wheels.hashes] +sha256 = "89ca642c5bf0101157a09366be69fad0379db1f700ae39a920e103234573670e" + +[[packages]] +name = "wheel-filename" +version = "1.4.2" +marker = "\"dev\" in dependency_groups or \"pkg-meta\" in dependency_groups" +requires-python = ">=3.8" +index = "https://pypi.org/simple/" + +[packages.sdist] +name = "wheel_filename-1.4.2.tar.gz" +upload-time = 2024-12-01 13:03:16.012739+00:00 +url = "https://files.pythonhosted.org/packages/38/be/726dab762b770d0417e505c58e26d661aac1ec0c831e483cda4817ca2417/wheel_filename-1.4.2.tar.gz" +size = 7911 + +[packages.sdist.hashes] +sha256 = "87891c465dcbb40b40394a906f01a93214bdd51aa5d25e3a9a59cae62bc298fd" + +[[packages.wheels]] +name = "wheel_filename-1.4.2-py3-none-any.whl" +upload-time = 2024-12-01 13:03:00.536117+00:00 +url = "https://files.pythonhosted.org/packages/b4/0f/6e97a3bc38cdde32e3ec49f8c0903fe3559ec9ec9db181782f0bb4417717/wheel_filename-1.4.2-py3-none-any.whl" +size = 6195 + +[packages.wheels.hashes] +sha256 = "3fa599046443d4ca830d06e3d180cd0a675d5871af0a68daa5623318bb4d17e3" + +[tool.nab] +nab-version = "0.0.22" +created-at = 2026-10-26 20:06:49.125271+00:00 +command-line = [ + "nab", + "lock", + "--all-groups", + "--all-extras", + "--no-cache", +] +input-path = "pyproject.toml" +mode = "universal" +python-specifier = ">=3.15,<3.16" +platforms = [ + "linux_x86_64", +] diff --git a/pyproject.toml b/pyproject.toml index 0a145e6e..93ee82b1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,14 +1,15 @@ [build-system] build-backend = "hatchling.build" requires = [ + "hatch-fancy-pypi-readme>=25.1", "hatch-vcs>=0.5", "hatchling>=1.29", ] [project] name = "platformdirs" +import-names = [ "platformdirs" ] description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." -readme = "README.md" keywords = [ "appdirs", "application", @@ -28,7 +29,6 @@ requires-python = ">=3.11" classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", - "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3 :: Only", @@ -42,6 +42,7 @@ classifiers = [ "Topic :: Software Development :: Libraries :: Python Modules", ] dynamic = [ + "readme", "version", ] urls.Changelog = "https://platformdirs.readthedocs.io/en/latest/changelog.html" @@ -70,12 +71,14 @@ test = [ ] type = [ "ty>=0.0.19", + { include-group = "docs-core" }, { include-group = "release" }, { include-group = "test" }, ] docs = [ + { include-group = "docs-core" }, + { include-group = "release" }, "furo>=2025.12.19", - "sphinx>=9.1", "sphinx-autodoc-typehints>=3.9.2", "sphinx-copybutton>=0.5.2", "sphinx-design>=0.7", @@ -84,14 +87,21 @@ docs = [ "sphinxcontrib-mermaid>=2", "sphinxcontrib-towncrier>=0.5.0a0", "sphinxext-opengraph>=0.13", - "towncrier>=24.8", "uv>=0.12.22", ] +build = [ + "cython>=3", + "hatch-fancy-pypi-readme>=25.1", + "hatch-vcs>=0.5", + "hatchling>=1.29", + "setuptools>=80", +] coverage = [ "covdefaults>=2.3", "coverage[toml]>=7.13.4", "diff-cover>=10.2", ] +docs-core = [ "sphinx>=9.1" ] fix = [ "pre-commit-uv>=4.2.1", ] @@ -101,11 +111,26 @@ pkg-meta = [ "uv>=0.10.7", ] release = [ - "towncrier>=24.8", + "release-creator>=4.1", + "towncrier>=26.9", +] +release-news = [ + "release-creator>=4.1", + "towncrier>=26.9", +] +release-notes = [ + "release-creator>=4.1", +] +release-prepare = [ + "prek>=0.5", + "release-creator>=4.1", + "towncrier>=26.9", ] [tool.hatch] version.source = "vcs" +metadata.hooks.fancy-pypi-readme.content-type = "text/markdown" +metadata.hooks.fancy-pypi-readme.fragments = [ { path = "README.md" } ] build.hooks.vcs.version-file = "src/platformdirs/version.py" build.targets.sdist.include = [ "/src", @@ -113,6 +138,16 @@ build.targets.sdist.include = [ "/tox.toml", ] +[tool.uv] +dependency-groups.dev = { requires-python = ">=3.15" } +dependency-groups.docs = { requires-python = ">=3.15" } +dependency-groups.docs-core = { requires-python = ">=3.12" } +dependency-groups.release = { requires-python = ">=3.15" } +dependency-groups.release-news = { requires-python = ">=3.15" } +dependency-groups.release-notes = { requires-python = ">=3.15" } +dependency-groups.release-prepare = { requires-python = ">=3.15" } +dependency-groups.type = { requires-python = ">=3.15" } + [tool.ruff] line-length = 120 format.preview = true @@ -187,13 +222,29 @@ html.skip_covered = false name = "platformdirs" directory = "docs/changelog" filename = "docs/changelog.rst" -template = "docs/changelog/template.jinja2" +template = "release_creator.fragments:template.rst.jinja2" title_format = false issue_format = ":pr:`{issue}`" +underlines = [ "*", "=", "-" ] type = [ - { directory = "breaking", name = "Backward incompatible changes", showcontent = true }, - { directory = "feature", name = "Features", showcontent = true }, - { directory = "bugfix", name = "Bug fixes", showcontent = true }, - { directory = "doc", name = "Improved documentation", showcontent = true }, - { directory = "packaging", name = "Packaging updates", showcontent = true }, + { directory = "feature", name = "Added", showcontent = true }, + { directory = "change", name = "Changes", showcontent = true }, + { directory = "bugfix", name = "Fixed", showcontent = true }, + { directory = "doc", name = "Documentation", showcontent = true }, + { directory = "breaking", name = "Breaking changes", showcontent = true }, + { directory = "security", name = "Security", showcontent = true }, + { directory = "performance", name = "Performance", showcontent = true }, + { directory = "deprecation", name = "Deprecated", showcontent = true }, + { directory = "removal", name = "Removed", showcontent = true }, + { directory = "packaging", name = "Packaging", showcontent = true }, ] + +[tool.nab] +mode = "universal" +base-group = "project-runtime" +uploaded-prior-to = "P7D" +decision-order = "stable" +matrix.python = ">=3.15,<3.16" +matrix.platforms = [ "linux_x86_64" ] +# temporary, delete after 2026-11-02 +packages.release-creator.uploaded-prior-to = 2026-10-26T18:24:46Z