Repository: jazzband/pip-tools Branch: main Commit: ea032fe82279 Files: 140 Total size: 617.0 KB Directory structure: gitextract_04gc2qn3/ ├── .bandit ├── .codecov.yml ├── .coveragerc ├── .flake8 ├── .git_archival.txt ├── .gitattributes ├── .github/ │ ├── CODEOWNERS │ ├── ISSUE_TEMPLATE/ │ │ ├── bug-report.md │ │ └── feature-request.md │ ├── PULL_REQUEST_TEMPLATE.md │ ├── actions/ │ │ └── cache-keys/ │ │ └── action.yml │ ├── chronographer.yml │ ├── reusables/ │ │ └── tox-dev/ │ │ └── workflow/ │ │ └── reusable-tox/ │ │ └── hooks/ │ │ └── post-tox-run/ │ │ └── action.yml │ └── workflows/ │ ├── ci.yml │ ├── cron.yml │ ├── release.yml │ └── reusable-qa.yml ├── .gitignore ├── .pre-commit-config.yaml ├── .pre-commit-hooks.yaml ├── .pymarkdown.yml ├── .readthedocs.yaml ├── CHANGELOG.md ├── CODE_OF_CONDUCT.md ├── CONTRIBUTING.md ├── LICENSE ├── MANIFEST.in ├── README.md ├── changelog.d/ │ ├── .draft_changelog_partial.md │ ├── .gitignore │ ├── .towncrier_template.md.jinja │ ├── 1142.feature.md │ ├── 2318.contrib.md │ ├── 2327.contrib.md │ ├── 2343.contrib.md │ └── README.md ├── docs/ │ ├── .gitignore │ ├── changelog.md │ ├── cli/ │ │ ├── index.md │ │ ├── pip-compile.md │ │ └── pip-sync.md │ ├── conf.py │ ├── contributing.md │ ├── index.md │ ├── pkg/ │ │ └── .gitignore │ ├── requirements.in │ └── requirements.txt ├── examples/ │ ├── django.in │ ├── flask.in │ ├── hypothesis.in │ ├── protection.in │ ├── readme/ │ │ ├── constraints.txt │ │ └── pyproject.toml │ └── sentry.in ├── piptools/ │ ├── __init__.py │ ├── __main__.py │ ├── _compat/ │ │ ├── __init__.py │ │ ├── _tomllib_compat.py │ │ ├── path_compat.py │ │ ├── pip_compat.py │ │ └── tempfile_compat.py │ ├── _internal/ │ │ ├── __init__.py │ │ ├── _pip_api/ │ │ │ ├── __init__.py │ │ │ ├── cli_options.py │ │ │ ├── install_requirements.py │ │ │ ├── package_finder.py │ │ │ └── pip_version.py │ │ └── _subprocess.py │ ├── build.py │ ├── cache.py │ ├── exceptions.py │ ├── locations.py │ ├── logging.py │ ├── py.typed │ ├── repositories/ │ │ ├── __init__.py │ │ ├── base.py │ │ ├── local.py │ │ └── pypi.py │ ├── resolver.py │ ├── scripts/ │ │ ├── __init__.py │ │ ├── _deprecations.py │ │ ├── compile.py │ │ ├── options.py │ │ └── sync.py │ ├── sync.py │ ├── utils.py │ └── writer.py ├── pyproject.toml ├── tests/ │ ├── __init__.py │ ├── conftest.py │ ├── constants.py │ ├── test_build.py │ ├── test_cache.py │ ├── test_circular_imports.py │ ├── test_cli_compile.py │ ├── test_cli_sync.py │ ├── test_data/ │ │ ├── fake-editables.json │ │ ├── fake-index.json │ │ ├── minimal_wheels/ │ │ │ ├── small_fake_a-0.1-py2.py3-none-any.whl │ │ │ ├── small_fake_a-0.2-py2.py3-none-any.whl │ │ │ ├── small_fake_a-0.3b1-py2.py3-none-any.whl │ │ │ ├── small_fake_b-0.1-py2.py3-none-any.whl │ │ │ ├── small_fake_b-0.2-py2.py3-none-any.whl │ │ │ ├── small_fake_b-0.3-py2.py3-none-any.whl │ │ │ ├── small_fake_multi_arch-0.1-py2.py3-none-manylinux1_i686.whl │ │ │ ├── small_fake_multi_arch-0.1-py2.py3-none-manylinux1_x86_64.whl │ │ │ ├── small_fake_multi_arch-0.1-py2.py3-none-win32.whl │ │ │ ├── small_fake_with_deps-0.1-py2.py3-none-any.whl │ │ │ ├── small_fake_with_deps_and_sub_deps-0.1-py2.py3-none-any.whl │ │ │ └── small_fake_with_unpinned_deps-0.1-py2.py3-none-any.whl │ │ └── packages/ │ │ ├── fake_with_deps/ │ │ │ ├── fake_with_deps/ │ │ │ │ └── __init__.py │ │ │ └── pyproject.toml │ │ ├── small_fake_a/ │ │ │ └── setup.py │ │ ├── small_fake_with_build_deps/ │ │ │ ├── backend/ │ │ │ │ └── backend.py │ │ │ ├── pyproject.toml │ │ │ └── setup.py │ │ ├── small_fake_with_deps/ │ │ │ └── setup.py │ │ ├── small_fake_with_deps_and_sub_deps/ │ │ │ └── setup.py │ │ ├── small_fake_with_pyproject/ │ │ │ └── pyproject.toml │ │ ├── small_fake_with_subdir/ │ │ │ └── subdir/ │ │ │ └── setup.py │ │ └── small_fake_with_unpinned_deps/ │ │ └── setup.py │ ├── test_fake_index.py │ ├── test_logging.py │ ├── test_minimal_upgrade.py │ ├── test_pip_compat.py │ ├── test_repository_local.py │ ├── test_repository_pypi.py │ ├── test_resolver.py │ ├── test_sync.py │ ├── test_top_level_editable.py │ ├── test_utils.py │ ├── test_writer.py │ ├── unit/ │ │ └── _internal/ │ │ ├── pip_api/ │ │ │ ├── test_cli_options.py │ │ │ ├── test_install_requirements.py │ │ │ ├── test_package_finder.py │ │ │ └── test_pip_version.py │ │ └── test_subprocess.py │ └── utils.py ├── towncrier.toml └── tox.ini ================================================ FILE CONTENTS ================================================ ================================================ FILE: .bandit ================================================ [bandit] exclude: tests,.tox,.eggs,.venv,.git skips: B101 ================================================ FILE: .codecov.yml ================================================ --- codecov: notify: manual_trigger: true # prevent notifications until we notify Codecov require_ci_to_pass: false comment: false # avoid spamming reviews ... ================================================ FILE: .coveragerc ================================================ [run] plugins = covdefaults omit = piptools/_compat/* [report] include = piptools/*, tests/* fail_under = 99 ================================================ FILE: .flake8 ================================================ [flake8] max-line-length = 100 # E203 conflicts with PEP8; see https://github.com/psf/black#slices extend-ignore = E203 # flake8-pytest-style # PT001: pytest-fixture-no-parentheses = true # PT006: pytest-parametrize-names-type = tuple # PT007: pytest-parametrize-values-type = tuple pytest-parametrize-values-row-type = tuple # PT023: pytest-mark-no-parentheses = true # flake8-typing-as-t # TYT02: typing-as-t-imported-name = _t ================================================ FILE: .git_archival.txt ================================================ node: $Format:%H$ node-date: $Format:%cI$ describe-name: $Format:%(describe:tags=true,match=v[0-9]*[0-9])$ ================================================ FILE: .gitattributes ================================================ # fill in placeholders when `git archive` is used, setuptools-scm support .git_archival.txt export-subst ================================================ FILE: .github/CODEOWNERS ================================================ /.github/ @jazzband/pip-tools-leads /tox.ini @jazzband/pip-tools-leads ================================================ FILE: .github/ISSUE_TEMPLATE/bug-report.md ================================================ --- name: Bug report about: Create a report to help us improve --- #### Environment Versions 1. OS Type 1. Python version: `$ python -V` 1. pip version: `$ pip --version` 1. pip-tools version: `$ pip-compile --version` #### Steps to replicate 1. ... 2. ... 3. ... #### Expected result ... #### Actual result ... ================================================ FILE: .github/ISSUE_TEMPLATE/feature-request.md ================================================ --- name: Feature request about: Suggest an idea for this project --- #### What's the problem this feature will solve? #### Describe the solution you'd like #### Alternative Solutions #### Additional context ================================================ FILE: .github/PULL_REQUEST_TEMPLATE.md ================================================ ##### Contributor checklist - [ ] Included tests for the changes. - [ ] A change note is created in `changelog.d/` (see [`changelog.d/README.md`] for instructions) or the PR text says "no changelog needed". [`changelog.d/README.md`]: https://github.com/jazzband/pip-tools/blob/main/changelog.d/#readme ##### Maintainer checklist - [ ] If no changelog is needed, apply the `bot:chronographer:skip` label. - [ ] Assign the PR to an existing or new milestone for the target version (following Semantic Versioning). ================================================ FILE: .github/actions/cache-keys/action.yml ================================================ --- name: placeholder description: placeholder outputs: cache-key-for-dep-files: description: >- A cache key string derived from the dependency declaration files. value: ${{ steps.calc-cache-key-files.outputs.files-hash-key }} runs: using: composite steps: - name: >- Calculate dependency files' combined hash value for use in the cache key id: calc-cache-key-files run: | from os import environ from pathlib import Path FILE_APPEND_MODE = 'a' files_derived_hash = '${{ hashFiles( 'tox.ini', 'pyproject.toml', '.pre-commit-config.yaml', 'pytest.ini', 'dependencies/**', 'dependencies/*/**', 'setup.cfg' ) }}' print(f'Computed file-derived hash is {files_derived_hash}.') with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print( f'files-hash-key={files_derived_hash}', file=outputs_file, ) shell: python ... ================================================ FILE: .github/chronographer.yml ================================================ branch-protection-check-name: Change log entry action-hints: check-title-prefix: "Chronographer: " external-docs-url: https://pip-tools.rtfd.io/en/latest/contributing/#adding-change-notes-with-prs inline-markdown: | See [the changelog contribution docs] for news fragment authoring gotchas. [the changelog contribution docs]: https://pip-tools.rtfd.io/en/latest/contributing/#adding-change-notes-with-prs enforce-name: suffix: .md ================================================ FILE: .github/reusables/tox-dev/workflow/reusable-tox/hooks/post-tox-run/action.yml ================================================ --- inputs: calling-job-context: description: A JSON with the calling job inputs type: string current-job-steps: description: >- The `$ {{ steps }}` context passed from the reusable workflow's tox job encoded as a JSON string. The caller passes it this input as follows: `current-job-steps: $ {{ toJSON(steps) }}`. type: string job-dependencies-context: default: >- {} description: >- The `$ {{ needs }}` context passed from the calling workflow encoded as a JSON string. The caller is expected to form this input as follows: `job-dependencies-context: $ {{ toJSON(needs) }}`. required: false type: string runs: using: composite steps: - name: Verify that the artifacts with expected names got created if: fromJSON(inputs.calling-job-context).toxenv == 'build-dists' run: > # Verify that the artifacts with expected names got created ls -1 'dist/${{ fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.sdist-artifact-name }}' 'dist/${{ fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.wheel-artifact-name }}' shell: bash - name: Store the distribution packages if: fromJSON(inputs.calling-job-context).toxenv == 'build-dists' uses: actions/upload-artifact@v4 with: name: >- ${{ fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.dists-artifact-name }} # NOTE: Exact expected file names are specified here # NOTE: as a safety measure — if anything weird ends # NOTE: up being in this dir or not all dists will be # NOTE: produced, this will fail the workflow. path: | dist/${{ fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.sdist-artifact-name }} dist/${{ fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.wheel-artifact-name }} retention-days: >- ${{ fromJSON( fromJSON( inputs.job-dependencies-context ).pre-setup.outputs.release-requested ) && 90 || 30 }} ... ================================================ FILE: .github/workflows/ci.yml ================================================ name: CI on: merge_group: pull_request: push: branches: - main tags: - v* workflow_call: inputs: cpython-pip-version: description: >- A JSON string with pip versions to test against under CPython. required: false type: string cpython-versions: description: >- A JSON string with CPython versions to test against. required: false type: string release-version: description: >- Target PEP440-compliant version to release. Any leading `v` will be stripped off. required: false type: string release-committish: default: '' description: >- The commit to be released to PyPI and tagged in Git as `release-version`. Normally, you should keep this empty. type: string outputs: dists-artifact-name: description: Workflow artifact name containing dists. value: ${{ jobs.pre-setup.outputs.dists-artifact-name }} is-upstream-repository: description: >- A flag representing whether the workflow runs in the upstream repository or a fork. value: ${{ jobs.pre-setup.outputs.is-upstream-repository }} project-name: description: PyPI project name. value: ${{ jobs.pre-setup.outputs.project-name }} project-version: description: PyPI project version string. value: ${{ jobs.pre-setup.outputs.dist-version }} concurrency: group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }} cancel-in-progress: true env: FORCE_COLOR: 1 # Request colored output from CLI tools supporting it MYPY_FORCE_COLOR: 1 # MyPy's color enforcement PIP_DISABLE_PIP_VERSION_CHECK: 1 PIP_NO_PYTHON_VERSION_WARNING: 1 PIP_NO_WARN_SCRIPT_LOCATION: 1 PRE_COMMIT_COLOR: 1 PY_COLORS: 1 # Recognized by the `py` package, dependency of `pytest` TOX_PARALLEL_NO_SPINNER: 1 TOX_TESTENV_PASSENV: >- FORCE_COLOR MYPY_FORCE_COLOR NO_COLOR PY_COLORS PYTEST_THEME PYTEST_THEME_MODE PRE_COMMIT_COLOR UPSTREAM_REPOSITORY_ID: >- 5746963 jobs: pre-setup: name: ⚙️ Pre-set global build settings runs-on: ubuntu-latest timeout-minutes: 2 # network is slow sometimes when fetching from Git defaults: run: shell: python outputs: # NOTE: These aren't env vars because the `${{ env }}` context is # NOTE: inaccessible when passing inputs to reusable workflows. dists-artifact-name: python-package-distributions dist-version: >- ${{ steps.normalize-dist-version.outputs.dist-version }} project-name: ${{ steps.metadata.outputs.project-name }} release-requested: >- ${{ steps.request-check.outputs.release-requested || false }} cache-key-for-dep-files: >- ${{ steps.calc-cache-key-files.outputs.cache-key-for-dep-files }} sdist-artifact-name: ${{ steps.artifact-name.outputs.sdist }} wheel-artifact-name: ${{ steps.artifact-name.outputs.wheel }} is-upstream-repository: >- ${{ toJSON(env.UPSTREAM_REPOSITORY_ID == github.repository_id) }} steps: - name: Switch to using Python 3.14 by default uses: actions/setup-python@v6 with: python-version: 3.14 - name: >- Mark the build as untagged '${{ github.event.repository.default_branch }}' branch build id: untagged-check if: >- github.event_name == 'push' && github.ref_type == 'branch' && github.ref_name == github.event.repository.default_branch run: | from os import environ from pathlib import Path FILE_APPEND_MODE = 'a' with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print('is-untagged-devel=true', file=outputs_file) - name: Mark the build as "release request" id: request-check if: inputs.release-version != '' run: | from os import environ from pathlib import Path FILE_APPEND_MODE = 'a' with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print('release-requested=true', file=outputs_file) - name: Check out src from Git uses: actions/checkout@v4 with: fetch-depth: >- ${{ steps.request-check.outputs.release-requested == 'true' && 1 || 0 }} ref: ${{ inputs.release-committish }} - name: Scan static PEP 621 core packaging metadata id: metadata run: | from os import environ from pathlib import Path from tomllib import loads as parse_toml_from_string FILE_APPEND_MODE = 'a' pyproject_toml_txt = Path('pyproject.toml').read_text() metadata = parse_toml_from_string(pyproject_toml_txt)['project'] project_name = metadata["name"] with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print(f'project-name={project_name}', file=outputs_file) - name: >- Calculate dependency files' combined hash value for use in the cache key if: >- steps.request-check.outputs.release-requested != 'true' id: calc-cache-key-files uses: ./.github/actions/cache-keys - name: Set up pip cache if: >- steps.request-check.outputs.release-requested != 'true' uses: re-actors/cache-python-deps@release/v1 with: cache-key-for-dependency-files: >- ${{ steps.calc-cache-key-files.outputs.cache-key-for-dep-files }} - name: Drop Git tags from HEAD for non-release requests if: >- steps.request-check.outputs.release-requested != 'true' run: >- git tag --points-at HEAD | xargs git tag --delete shell: bash -eEuxo pipefail {0} - name: Set up versioning prerequisites if: >- steps.request-check.outputs.release-requested != 'true' run: >- python -m pip install --user setuptools-scm shell: bash -eEuxo pipefail {0} - name: Set the current dist version from Git if: steps.request-check.outputs.release-requested != 'true' id: scm-version run: | from os import environ from pathlib import Path import setuptools_scm FILE_APPEND_MODE = 'a' ver = setuptools_scm.get_version(local_scheme='dirty-tag') with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print(f'dist-version={ver}', file=outputs_file) print( f'dist-version-for-filenames={ver.replace("+", "-")}', file=outputs_file, ) - name: Normalize dist version id: normalize-dist-version run: | from os import environ from pathlib import Path FILE_APPEND_MODE = 'a' dist_version = "${{ steps.request-check.outputs.release-requested == 'true' && inputs.release-version || steps.scm-version.outputs.dist-version }}".lstrip("v") with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print( f"dist-version={dist_version}", file=outputs_file, ) - name: Set the expected dist artifact names id: artifact-name env: PROJECT_NAME: ${{ steps.metadata.outputs.project-name }} run: | from os import environ from pathlib import Path FILE_APPEND_MODE = 'a' whl_file_prj_base_name = environ['PROJECT_NAME'].replace('-', '_') sdist_file_prj_base_name = ( whl_file_prj_base_name. replace('.', '_'). lower() ) dist_version = "${{ steps.normalize-dist-version.outputs.dist-version }}" with Path(environ['GITHUB_OUTPUT']).open( mode=FILE_APPEND_MODE, ) as outputs_file: print( f"sdist={sdist_file_prj_base_name !s}-{dist_version}.tar.gz", file=outputs_file, ) print( f"wheel={whl_file_prj_base_name !s}-{dist_version}-py3-none-any.whl", file=outputs_file, ) build: name: >- 📦 Build dists needs: - pre-setup # transitive, for accessing settings uses: tox-dev/workflow/.github/workflows/reusable-tox.yml@617ca35caa695c572377861016677905e58a328c # yamllint disable-line rule:line-length with: cache-key-for-dependency-files: >- ${{ needs.pre-setup.outputs.cache-key-for-dep-files }} check-name: Build dists under 🐍3.12 checkout-src-git-committish: >- ${{ inputs.release-committish }} checkout-src-git-fetch-depth: >- ${{ fromJSON(needs.pre-setup.outputs.release-requested) && 1 || 0 }} job-dependencies-context: >- # context for hooks ${{ toJSON(needs) }} python-version: 3.12 runner-vm-os: ubuntu-latest timeout-minutes: 2 toxenv: build-dists xfail: false linters: name: Linters uses: ./.github/workflows/reusable-qa.yml test: name: ${{ matrix.os }} / ${{ matrix.python-version }} / ${{ matrix.pip-version }} runs-on: ${{ matrix.os }}-latest timeout-minutes: 15 strategy: fail-fast: false matrix: os: - Ubuntu - Windows - macOS python-version: >- ${{ fromJSON( inputs.cpython-versions && inputs.cpython-versions || '["3.9", "3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"]' ) }} pip-version: >- ${{ fromJSON( inputs.cpython-pip-version && inputs.cpython-pip-version || '["supported", "lowest"]' ) }} env: TOXENV: >- pip${{ matrix.pip-version }}${{ !inputs.cpython-pip-version && '-coverage' || '' }} steps: - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} from GitHub id: python-install if: "!endsWith(matrix.python-version, '-dev')" uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Set up Python ${{ matrix.python-version }} from deadsnakes if: endsWith(matrix.python-version, '-dev') uses: deadsnakes/action@v2.1.1 with: python-version: ${{ matrix.python-version }} - name: Log python version info (${{ matrix.python-version }}) run: python --version --version - name: Get pip cache dir id: pip-cache shell: bash run: | echo "dir=$(pip cache dir)" >> "${GITHUB_OUTPUT}" - name: Pip cache uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: >- ${{ runner.os }}-pip-${{ hashFiles('setup.cfg') }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('tox.ini') }}-${{ hashFiles('.pre-commit-config.yaml') }} restore-keys: | ${{ runner.os }}-pip- ${{ runner.os }}- - name: Install test dependencies run: python -m pip install -U tox virtualenv - name: Prepare test environment # NOTE: `--parallel-live` is a workaround for the regression in # NOTE: the upstream tox project that made the # NOTE: `TOX_PARALLEL_NO_SPINNER=1` env var auto-enable parallelism # NOTE: and disable output from the tox environments. # # Ref: https://github.com/tox-dev/tox/issues/3193 run: tox -vv --notest -p auto --parallel-live - name: Test pip ${{ matrix.pip-version }} # NOTE: `--parallel-live` is a workaround for the regression in # NOTE: the upstream tox project that made the # NOTE: `TOX_PARALLEL_NO_SPINNER=1` env var auto-enable parallelism # NOTE: and disable output from the tox environments. # # Ref: https://github.com/tox-dev/tox/issues/3193 run: tox --skip-pkg-install --parallel-live - name: Re-run the failing tests with maximum verbosity if: >- !cancelled() && failure() run: >- # `exit 1` makes sure that the job remains red with flaky runs python -Xutf8 -Im tox --parallel=auto --parallel-live --skip-missing-interpreters=false --skip-pkg-install -vvvvv -- --continue-on-collection-errors --full-trace --last-failed ${{ !inputs.cpython-pip-version && '--no-cov' || '' }} --numprocesses=0 --showlocals --trace-config -rA -vvvvv && exit 1 shell: bash - name: Upload coverage to Codecov if: >- !cancelled() && !inputs.cpython-pip-version uses: codecov/codecov-action@v5 with: files: ./coverage.xml flags: >- CI-GHA, OS-${{ runner.os }}, VM-${{ matrix.os }}, Py-${{ steps.python-install.outputs.python-version }}, Pip-${{ matrix.pip-version }} name: >- OS-${{ runner.os }}, VM-${{ matrix.os }}, Py-${{ steps.python-install.outputs.python-version }}, Pip-${{ matrix.pip-version }} pypy: name: ${{ matrix.os }} / ${{ matrix.python-version }} / ${{ matrix.pip-version }} runs-on: ${{ matrix.os }}-latest timeout-minutes: 9 strategy: fail-fast: false matrix: os: - Ubuntu - MacOS - Windows python-version: - pypy-3.10 pip-version: - supported env: TOXENV: pip${{ matrix.pip-version }} steps: - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Get pip cache dir id: pip-cache shell: bash run: | echo "dir=$(pip cache dir)" >> "${GITHUB_OUTPUT}" - name: Pip cache uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: >- ${{ runner.os }}-pip-${{ hashFiles('setup.cfg') }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('tox.ini') }}-${{ hashFiles('.pre-commit-config.yaml') }} restore-keys: | ${{ runner.os }}-pip- ${{ runner.os }}- - name: Install tox run: pip install tox - name: Prepare test environment # NOTE: `--parallel-live` is a workaround for the regression in # NOTE: the upstream tox project that made the # NOTE: `TOX_PARALLEL_NO_SPINNER=1` env var auto-enable parallelism # NOTE: and disable output from the tox environments. # # Ref: https://github.com/tox-dev/tox/issues/3193 run: tox --notest -p auto --parallel-live - name: Test pip ${{ matrix.pip-version }} # NOTE: `--parallel-live` is a workaround for the regression in # NOTE: the upstream tox project that made the # NOTE: `TOX_PARALLEL_NO_SPINNER=1` env var auto-enable parallelism # NOTE: and disable output from the tox environments. # # Ref: https://github.com/tox-dev/tox/issues/3193 run: tox --skip-pkg-install --parallel-live - name: Re-run the failing tests with maximum verbosity if: >- !cancelled() && failure() run: >- # `exit 1` makes sure that the job remains red with flaky runs python -Xutf8 -Im tox --parallel=auto --parallel-live --skip-missing-interpreters=false --skip-pkg-install -vvvvv -- --continue-on-collection-errors --full-trace --last-failed --numprocesses=0 --showlocals --trace-config -rA -vvvvv && exit 1 shell: bash coverage-summary: name: Coverage processing if: >- !cancelled() runs-on: ubuntu-latest timeout-minutes: 1 needs: - test steps: - name: Notify Codecov that all coverage reports have been uploaded if: >- !cancelled() uses: codecov/codecov-action@v5 with: fail_ci_if_error: true run_command: send-notifications zizmor: name: 🌈 zizmor permissions: security-events: write # yamllint disable-line rule:line-length uses: zizmorcore/workflow/.github/workflows/reusable-zizmor.yml@1e20adb0862e932363a4d85d68c92e5cc6fcb5d4 check: # This job does nothing and is only used for the branch protection if: always() needs: - linters - pypy - test - zizmor runs-on: ubuntu-latest timeout-minutes: 1 steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@afee1c1eac2a506084c274e9c02c8e0687b48d9e with: jobs: ${{ toJSON(needs) }} ================================================ FILE: .github/workflows/cron.yml ================================================ name: Cron on: schedule: # Run everyday at 03:53 UTC - cron: 53 3 * * * jobs: main: name: CI uses: ./.github/workflows/ci.yml with: cpython-versions: >- ["3.10", "3.11", "3.12", "3.13", "3.14", "3.14t"] cpython-pip-version: >- ["main", "latest", "supported", "lowest"] ================================================ FILE: .github/workflows/release.yml ================================================ --- name: 📦 Packaging on: release: types: - published env: FORCE_COLOR: 1 # Request colored output from CLI tools supporting it MYPY_FORCE_COLOR: 1 # MyPy's color enforcement PIP_DISABLE_PIP_VERSION_CHECK: 1 # Hide "there's a newer pip" message PIP_NO_PYTHON_VERSION_WARNING: 1 # Hide "this Python is deprecated" message PIP_NO_WARN_SCRIPT_LOCATION: 1 # Hide "script dir is not in $PATH" message PRE_COMMIT_COLOR: always PY_COLORS: 1 # Recognized by the `py` package, dependency of `pytest` PYTHONIOENCODING: utf-8 PYTHONUTF8: 1 TOX_PARALLEL_NO_SPINNER: 1 # Disable tox's parallel run spinner animation TOX_TESTENV_PASSENV: >- # Make tox-wrapped tools see color requests FORCE_COLOR MYPY_FORCE_COLOR NO_COLOR PIP_DISABLE_PIP_VERSION_CHECK PIP_NO_PYTHON_VERSION_WARNING PIP_NO_WARN_SCRIPT_LOCATION PRE_COMMIT_COLOR PY_COLORS PYTEST_THEME PYTEST_THEME_MODE PYTHONIOENCODING PYTHONLEGACYWINDOWSSTDIO PYTHONUTF8 run-name: >- ${{ github.event.action == 'published' && format('📦 Releasing {0}...', github.ref_name) || format('🌱 Smoke-testing packaging for commit {0}', github.sha) }} triggered by: ${{ github.event_name }} of ${{ github.ref }} ${{ github.ref_type }} (workflow run ID: ${{ github.run_id }}; number: ${{ github.run_number }}; attempt: ${{ github.run_attempt }}) jobs: build-and-test: name: >- 📦 ${{ github.ref_name }} [mode: ${{ github.event.action == 'published' && 'release' || 'nightly' }}] uses: ./.github/workflows/ci.yml with: release-version: ${{ github.ref_name }} release-committish: '' publish-pypi: name: >- 📦 Publish v${{ needs.build-and-test.outputs.project-version }} to PyPI needs: - build-and-test if: >- github.event.action == 'published' && fromJSON(needs.build-and-test.outputs.is-upstream-repository) runs-on: ubuntu-latest timeout-minutes: 2 # docker+network are slow sometimes environment: name: pypi url: >- https://pypi.org/project/${{ needs.build-and-test.outputs.project-name }}/${{ needs.build-and-test.outputs.project-version }} permissions: id-token: write # PyPI Trusted Publishing (OIDC) steps: - name: Download all the dists uses: actions/download-artifact@v4 with: name: >- ${{ needs.build-and-test.outputs.dists-artifact-name }} path: dist/ - name: >- 📦 Publish v${{ needs.build-and-test.outputs.project-version }} to PyPI 🔏 uses: pypa/gh-action-pypi-publish@release/v1 - name: Clean up the publish attestation leftovers run: rm -fv dist/*.publish.attestation - name: Upload packages to Jazzband uses: pypa/gh-action-pypi-publish@release/v1 with: user: jazzband password: ${{ secrets.JAZZBAND_RELEASE_KEY }} repository-url: >- https://jazzband.co/projects/${{ needs.build-and-test.outputs.project-name }}/upload ================================================ FILE: .github/workflows/reusable-qa.yml ================================================ name: QA on: workflow_call: jobs: qa: name: ${{ matrix.toxenv }} runs-on: ubuntu-latest timeout-minutes: 2 # network is slow sometimes strategy: fail-fast: false matrix: toxenv: - readme - build-docs - linkcheck-docs - changelog-draft python-version: - "3.13" env: PY_COLORS: 1 TOXENV: ${{ matrix.toxenv }} TOX_PARALLEL_NO_SPINNER: 1 steps: - uses: actions/checkout@v5 - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@v6 with: python-version: ${{ matrix.python-version }} - name: Get pip cache dir id: pip-cache run: | echo "dir=$(pip cache dir)" >> "${GITHUB_OUTPUT}" - name: Pip cache uses: actions/cache@v4 with: path: ${{ steps.pip-cache.outputs.dir }} key: >- ${{ runner.os }}-pip-${{ hashFiles('setup.cfg') }}-${{ hashFiles('pyproject.toml') }}-${{ hashFiles('tox.ini') }}-${{ hashFiles('.pre-commit-config.yaml') }} restore-keys: | ${{ runner.os }}-pip- ${{ runner.os }}- - name: Prepare cache key id: cache-key run: echo "sha-256=$(python -VV | sha256sum | cut -d' ' -f1)" >> "${GITHUB_OUTPUT}" - uses: actions/cache@v4 with: path: ~/.cache/pre-commit key: pre-commit|${{ steps.cache-key.outputs.sha-256 }}|${{ hashFiles('.pre-commit-config.yaml') }} - name: Install tox run: pip install tox - name: Prepare test environment run: tox -vv --notest -p auto --parallel-live - name: Test ${{ matrix.toxenv }} run: tox --skip-pkg-install ================================================ FILE: .gitignore ================================================ # Ignore cram test output *.t.err # Python cruft *.pyc # Virtualenvs .envrc .direnv .venv venv/ # Testing .pytest_cache/ .tox htmlcov # Build output build dist *.egg-info .coverage .coverage.* coverage.xml .cache # IDE .idea # Test files requirements.in requirements.txt .eggs/ ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/psf/black-pre-commit-mirror rev: 26.3.1 hooks: - id: black args: [--target-version=py39] - repo: https://github.com/PyCQA/isort rev: 8.0.1 hooks: - id: isort - repo: https://github.com/asottile/pyupgrade rev: v3.21.2 hooks: - id: pyupgrade args: [--py39-plus] - repo: https://github.com/python-jsonschema/check-jsonschema.git rev: 0.37.0 hooks: - id: check-github-actions - id: check-github-workflows - id: check-jsonschema alias: enforce-gha-timeouts name: Check GitHub Workflows set timeout-minutes args: - --builtin-schema - github-workflows-require-timeout files: ^\.github/workflows/[^/]+$ types: - yaml - id: check-readthedocs - repo: https://github.com/PyCQA/flake8 rev: 7.3.0 hooks: - id: flake8 additional_dependencies: - flake8-pytest-style == 2.2.0 - flake8-typing-as-t == 1.1.0 - repo: https://github.com/pre-commit/mirrors-mypy rev: v1.19.1 hooks: - id: mypy # Avoid error: Duplicate module named 'setup' # https://github.com/python/mypy/issues/4008 # Keep exclude in sync with mypy own excludes exclude: ^tests/test_data/ additional_dependencies: - click==8.0.1 - pep517==0.10.0 - toml==0.10.2 - pip==20.3.4 - build==1.0.0 - pyproject_hooks==1.0.0 - pytest==7.4.2 - repo: https://github.com/PyCQA/bandit rev: 1.9.4 hooks: - id: bandit args: [--ini, .bandit] exclude: ^tests/ - repo: local hooks: - id: changelogs-md name: changelog filenames language: fail entry: >- Changelog files must be named ####.( highlights | bugfix | feature | deprecation | breaking | doc | packaging | contrib | misc | afterword )(.#)?(.md)? exclude: >- (?x) ^ changelog.d/( \.gitignore |\.towncrier_template\.md\.jinja |\.draft_changelog_partial\.md |README\.md |(\d+|[0-9a-f]{8}|[0-9a-f]{7}|[0-9a-f]{40}|\+[^.]+)\.( highlights |bugfix |feature |deprecation |breaking |doc |packaging |contrib |misc |afterword )(\.\d+)?(\.md)? ) $ files: ^changelog\.d/ types: [] types_or: - file - symlink - repo: https://github.com/rhysd/actionlint.git rev: v1.7.11 hooks: - id: actionlint additional_dependencies: # actionlint has a shellcheck integration which extracts shell scripts in `run:` steps from GitHub Actions # and checks these with shellcheck. # The integration only works if shellcheck is installed. - "github.com/wasilibs/go-shellcheck/cmd/shellcheck@v0.11.1" - repo: https://github.com/jackdewinter/pymarkdown.git rev: v0.9.36 hooks: - id: pymarkdown alias: md-changelog name: PyMarkdown (published change log) args: # NOTE: `no-emphasis-as-heading` trips on dates under version # NOTE: titles. Wrapping the dates with `