diff --git a/.cspell.json b/.cspell.json index b2bbcc7b..07938e9e 100644 --- a/.cspell.json +++ b/.cspell.json @@ -36,6 +36,7 @@ "**/.cspell.json", ".editorconfig", ".envrc", + ".github/dependabot.yml", ".gitignore", ".pre-commit-config.yaml", ".prettierignore", @@ -44,6 +45,7 @@ "pyproject.toml" ], "ignoreWords": [ + "PYTEST_XDIST_WORKER_COUNT", "elif", "ipynb", "mhutchie", diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 90891ae8..c658ead2 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,16 +1,14 @@ version: 2 + +multi-ecosystem-groups: + lock: + assignees: [redeboer] + commit-message: { prefix: MAINT } + schedule: { interval: quarterly } + updates: - package-ecosystem: github-actions directory: "/" - assignees: - - redeboer - commit-message: - prefix: MAINT - groups: - actions: - patterns: - - "*" - labels: - - ⬆️ Lock - schedule: - interval: monthly + labels: [⬆️ Lock] + multi-ecosystem-group: lock + patterns: ["*"] diff --git a/.github/workflows/cd.yml b/.github/workflows/cd.yml index 2def5ff7..110ca129 100644 --- a/.github/workflows/cd.yml +++ b/.github/workflows/cd.yml @@ -9,11 +9,11 @@ on: jobs: milestone: if: startsWith(github.ref, 'refs/tags') - uses: ComPWA/actions/.github/workflows/close-milestone.yml@v3 + uses: ComPWA/actions/.github/workflows/close-milestone.yml@v4 push-to-version-branches: name: Push to version branches if: startsWith(github.ref, 'refs/tags') && !github.event.release.prerelease - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 - name: Configure Git credentials diff --git a/.github/workflows/ci-docs.yml b/.github/workflows/ci-docs.yml index ab0d35fa..0aac93a7 100644 --- a/.github/workflows/ci-docs.yml +++ b/.github/workflows/ci-docs.yml @@ -12,9 +12,6 @@ on: default: "3.13" required: false type: string - specific-pip-packages: - required: false - type: string jobs: linkcheck: @@ -29,7 +26,6 @@ jobs: with: apt-packages: ${{ inputs.apt-packages }} python-version: ${{ inputs.python-version }} - specific-pip-packages: ${{ inputs.specific-pip-packages }} gh-pages: name: Upload to GitHub Pages @@ -43,7 +39,7 @@ jobs: permissions: pages: write id-token: write - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - id: deployment uses: actions/deploy-pages@v4 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b95a35d9..b0b75404 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -17,15 +17,9 @@ on: - epic/* - "[0-9]+.[0-9]+.x" workflow_dispatch: - inputs: - specific-pip-packages: - description: Run CI with specific pip packages - required: false - type: string jobs: style: - if: inputs.specific-pip-packages == '' secrets: token: ${{ secrets.PAT }} - uses: ComPWA/actions/.github/workflows/pre-commit.yml@v3.0 + uses: ComPWA/actions/.github/workflows/pre-commit.yml@v4.0 diff --git a/.github/workflows/clean-caches.yml b/.github/workflows/clean-caches.yml index 2de0c959..1d3abcc7 100644 --- a/.github/workflows/clean-caches.yml +++ b/.github/workflows/clean-caches.yml @@ -14,9 +14,9 @@ on: jobs: cleanup: name: Remove caches - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - - uses: ComPWA/actions/clean-caches@v3 + - uses: ComPWA/actions/clean-caches@v4 with: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} ref: ${{ inputs.ref }} diff --git a/.github/workflows/close-milestone.yml b/.github/workflows/close-milestone.yml index 838a6b22..d8a56b36 100644 --- a/.github/workflows/close-milestone.yml +++ b/.github/workflows/close-milestone.yml @@ -3,7 +3,7 @@ on: jobs: close-milestone: - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: mhutchie/update-milestone-on-release@master with: diff --git a/.github/workflows/docnb.yml b/.github/workflows/docnb.yml index 9f9fe69c..4fb6e01e 100644 --- a/.github/workflows/docnb.yml +++ b/.github/workflows/docnb.yml @@ -8,9 +8,6 @@ on: default: "3.13" required: false type: string - specific-pip-packages: - required: false - type: string jobs: docnb: @@ -30,7 +27,6 @@ jobs: **/pyproject.toml **/uv.lock - name: Fetch Jupyter cache - if: inputs.specific-pip-packages == '' uses: actions/cache@v5 with: key: | @@ -39,25 +35,21 @@ jobs: jupyter-cache-${{ hashFiles('.constraints/py3.*.txt', 'src/**.py', 'uv.lock') }} path: | ./docs/_build/.jupyter_cache - - uses: ComPWA/actions/cache-sympy@v3 + - uses: ComPWA/actions/cache-sympy@v4 - if: inputs.apt-packages run: | sudo apt-get update -y sudo apt-get install -y ${{ inputs.apt-packages }} - if: hashFiles('**/Project.toml') - uses: ComPWA/actions/install-julia@v3 + uses: ComPWA/actions/install-julia@v4 with: ijulia: true - id: task-runner - uses: ComPWA/actions/determine-task-runner@v3 + uses: ComPWA/actions/determine-task-runner@v4 - name: Build documentation and run notebooks (poe) if: steps.task-runner.outputs.value == 'poe' - run: |- - uv run \ - --group doc \ - --with poethepoet \ - poe doc - - uses: prefix-dev/setup-pixi@v0.9.3 + run: uvx --from poethepoet poe doc + - uses: prefix-dev/setup-pixi@v0.9.4 if: steps.task-runner.outputs.value == 'pixi' with: cache: true diff --git a/.github/workflows/get-pypi-name.yml b/.github/workflows/get-pypi-name.yml index cee9175c..6329fc1b 100644 --- a/.github/workflows/get-pypi-name.yml +++ b/.github/workflows/get-pypi-name.yml @@ -10,9 +10,9 @@ jobs: package-name: if: startsWith(github.ref, 'refs/tags') name: Determine package name - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim outputs: name: ${{ steps.package-name.outputs.name }} steps: - - uses: ComPWA/actions/get-pypi-name@v3 + - uses: ComPWA/actions/get-pypi-name@v4 id: package-name diff --git a/.github/workflows/linkcheck.yml b/.github/workflows/linkcheck.yml index 747b6da5..336acc76 100644 --- a/.github/workflows/linkcheck.yml +++ b/.github/workflows/linkcheck.yml @@ -28,17 +28,13 @@ jobs: sudo apt-get update -y sudo apt-get install -y ${{ inputs.apt-packages }} - id: task-runner - uses: ComPWA/actions/determine-task-runner@v3 + uses: ComPWA/actions/determine-task-runner@v4 - env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} if: steps.task-runner.outputs.value == 'poe' name: Run Sphinx linkcheck (poe) - run: |- - uv run \ - --group doc \ - --with poethepoet \ - poe linkcheck - - uses: prefix-dev/setup-pixi@v0.9.3 + run: uvx --from poethepoet poe linkcheck + - uses: prefix-dev/setup-pixi@v0.9.4 if: steps.task-runner.outputs.value == 'pixi' with: cache: true diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index cd4a6207..a42bdb1a 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -37,7 +37,7 @@ jobs: github.event_name == 'workflow_dispatch' outputs: exists: ${{ steps.pr-exists.outputs.exists }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 - name: List open pull requests @@ -77,7 +77,7 @@ jobs: if: >- github.event_name == 'pull_request' && github.event.pull_request.head.repo.full_name == github.repository - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim outputs: lock-upgrade: ${{ steps.check.outputs.lock-upgrade }} steps: @@ -122,7 +122,7 @@ jobs: needs: - pr-has-lock-label - pr-exists - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim outputs: lock-files: ${{ steps.check.outputs.lock-files }} steps: @@ -150,10 +150,10 @@ jobs: - find-lock-files outputs: matrix: ${{ steps.versions.outputs.matrix }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - id: versions - uses: ComPWA/actions/create-python-version-matrix@v3 + uses: ComPWA/actions/create-python-version-matrix@v4 pip-constraints: name: pip constraint files @@ -179,7 +179,7 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6 - - uses: prefix-dev/setup-pixi@v0.9.3 + - uses: prefix-dev/setup-pixi@v0.9.4 with: run-install: false - name: Update lock files @@ -200,7 +200,7 @@ jobs: - if: hashFiles('pixi.lock') == '' uses: julia-actions/setup-julia@v2 - if: hashFiles('pixi.lock') - uses: prefix-dev/setup-pixi@v0.9.3 + uses: prefix-dev/setup-pixi@v0.9.4 with: activate-environment: true - name: Update Julia Manifest.toml @@ -218,7 +218,22 @@ jobs: runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v6 - - uses: ComPWA/update-pre-commit@v1 + - uses: actions/setup-python@v6 + - uses: astral-sh/setup-uv@v7 + - env: + FORCE_COLOR: True + UV_SYSTEM_PYTHON: True + run: uvx --with pre-commit-uv pre-commit autoupdate -j$(nproc) + shell: bash + - name: Show changes + run: git diff --color --unified=0 + shell: bash + - uses: actions/upload-artifact@v6 + with: + if-no-files-found: error + include-hidden-files: true + name: pre-commit + path: .pre-commit-config.yaml uv-lock: name: uv.lock @@ -242,7 +257,7 @@ jobs: if: >- always() && needs.pr-has-lock-label.outputs.lock-upgrade == 'true' - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim needs: - julia - pip-constraints @@ -280,7 +295,7 @@ jobs: create-pr: name: Create PR - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim if: >- always() && needs.pr-exists.outputs.exists == 'false' diff --git a/.github/workflows/pr-linting.yml b/.github/workflows/pr-linting.yml index c43186e9..5d706181 100644 --- a/.github/workflows/pr-linting.yml +++ b/.github/workflows/pr-linting.yml @@ -26,7 +26,7 @@ jobs: check-title: if: github.event.pull_request.state == 'open' name: Check title - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 - run: npm install @compwa/commitlint-config diff --git a/.github/workflows/pre-commit.yml b/.github/workflows/pre-commit.yml index 2b161571..ec9417ff 100644 --- a/.github/workflows/pre-commit.yml +++ b/.github/workflows/pre-commit.yml @@ -20,16 +20,17 @@ on: env: DISABLE_PRE_COMMIT_UV_PATCH: True FORCE_COLOR: true + PRE_COMMIT_COLOR: always jobs: determine-hooks: name: Determine skipped pre-commit hooks outputs: skipped-hooks: ${{ steps.hooks.outputs.skipped-hooks }} - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - id: hooks - uses: ComPWA/actions/get-skipped-pre-commit-hooks@v3 + uses: ComPWA/actions/get-skipped-pre-commit-hooks@v4 pre-commit: name: Run local pre-commit hooks @@ -50,6 +51,7 @@ jobs: **/.pre-commit-config.yaml **/pyproject.toml **/uv.lock + cache-suffix: pre-commit - name: Fetch pre-commit cache uses: actions/cache@v5 with: @@ -58,10 +60,30 @@ jobs: restore-keys: | pre-commit-${{ runner.os }}-py${{ inputs.python-version }} path: ~/.cache/pre-commit/ - - id: uv-run - uses: ComPWA/actions/run-pre-commit@v3 + - run: | + uv tool install --python=${{ inputs.python-version }} poethepoet + uv tool install --python=${{ inputs.python-version }} --with pre-commit-uv pre-commit + - name: Determine style-check command + id: cmd + run: | + cmd="pre-commit run --all-files" + if [[ -f pixi.toml && $(grep -c "\[tasks.style\]" pixi.toml) -gt 0 ]]; then + cmd="pixi run style" + fi + if [[ -f pyproject.toml ]]; then + if [[ $(grep -c "\[tool.poe.tasks.style\]" pyproject.toml) -gt 0 ]]; then + cmd="poe style" + elif [[ $(grep -c "\[tool.pixi.tasks.style\]" pyproject.toml) -gt 0 ]]; then + cmd="pixi run style" + fi + fi + echo "cmd=$cmd" | tee -a $GITHUB_OUTPUT + - uses: prefix-dev/setup-pixi@v0.9.4 + if: contains(steps.cmd.outputs.cmd, 'pixi') + with: + cache: true - if: needs.determine-hooks.outputs.skipped-hooks == 'ALL' - run: ${{ steps.uv-run.outputs.cmd }} --with pre-commit-uv pre-commit run --all-files --color=always + run: ${{ steps.cmd.outputs.cmd }} - if: needs.determine-hooks.outputs.skipped-hooks != 'ALL' name: Run pre-commit hooks that don't work on pre-commit.ci run: |- @@ -70,7 +92,7 @@ jobs: export PRETTIER_LEGACY_CLI=1 fi for hook in $skipped_hooks; do - ${{ steps.uv-run.outputs.cmd }} --with pre-commit-uv pre-commit run $hook --all-files --color=always + ${{ steps.cmd.outputs.cmd }} $hook done - id: diff if: always() @@ -104,7 +126,7 @@ jobs: name: Push changes needs: - pre-commit - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 with: diff --git a/.github/workflows/push-to-version-branches.yml b/.github/workflows/push-to-version-branches.yml index 561d0385..8fea1c8f 100644 --- a/.github/workflows/push-to-version-branches.yml +++ b/.github/workflows/push-to-version-branches.yml @@ -5,7 +5,7 @@ jobs: push: name: Push to version branches if: startsWith(github.ref, 'refs/tags') && !github.event.release.prerelease - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: actions/checkout@v6 - name: Configure Git credentials diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml deleted file mode 100644 index d79d5949..00000000 --- a/.github/workflows/pytest.yml +++ /dev/null @@ -1,120 +0,0 @@ -env: - FORCE_COLOR: "1" - PYTHONHASHSEED: "0" - -on: - workflow_call: - inputs: - additional-extras: - description: Space-separated additional extras that need to be installed for the tests. - required: false - type: string - coverage-python-version: - default: "3.13" - required: false - type: string - coverage-target: - required: false - type: string - macos-python-version: - required: false - type: string - multithreaded: - default: true - required: false - type: boolean - skipped-python-versions: - required: false - type: string - specific-pip-packages: - required: false - type: string - test-output-path: - required: false - type: string - secrets: - CODECOV_TOKEN: - description: Token for uploading reports to Codecov. See https://docs.codecov.com/docs/codecov-uploader. - required: false - -jobs: - create-matrix: - name: Determine job matrix - outputs: - matrix: ${{ steps.set-matrix.outputs.matrix }} - runs-on: ubuntu-24.04 - steps: - - id: set-matrix - uses: ComPWA/actions/create-pytest-matrix@v3 - with: - coverage-python-version: ${{ inputs.coverage-python-version }} - coverage-target: ${{ inputs.coverage-target }} - macos-python-version: ${{ inputs.macos-python-version }} - skipped-python-versions: ${{ inputs.skipped-python-versions }} - - pytest: - name: Run unit tests - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - UV_PYTHON: ${{ matrix.python-version }} - needs: create-matrix - runs-on: ${{ matrix.runs-on }} - strategy: - fail-fast: false - matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }} - steps: - - uses: actions/checkout@v6 - - uses: astral-sh/setup-uv@v7 - with: - cache-dependency-glob: | - **/pyproject.toml - **/uv.lock - - uses: ComPWA/actions/cache-sympy@v3 - - id: extra - if: inputs.additional-extras - name: Determine extras to install - run: | - test_extras='' - for extra in ${{ inputs.additional-extras }}; do - test_extras="$test_extras --group $extra" - done - echo "extras=$test_extras" | tee -a $GITHUB_OUTPUT - - id: with - if: inputs.specific-pip-packages - name: Determine additional packages to install - run: | - additional_packages='' - for package in ${{ inputs.specific-pip-packages }}; do - additional_packages="$additional_packages --with $package" - done - echo "packages=$additional_packages" | tee -a $GITHUB_OUTPUT - - id: coverage - if: matrix.coverage-target - name: Determine pytest coverage flags - run: echo "flags=--cov-report=xml --cov=${{ matrix.coverage-target }}" | tee -a $GITHUB_OUTPUT - - id: multithreaded - if: inputs.multithreaded - name: Determine pytest multithreading flags - run: echo "flags=--numprocesses=auto" | tee -a $GITHUB_OUTPUT - - name: Run tests with pytest - run: >- - uv run \ - --group test \ - ${{ steps.extra.outputs.extras }} \ - --no-dev \ - ${{ steps.with.outputs.packages }} \ - pytest \ - ${{ steps.coverage.outputs.flags }} \ - ${{ steps.multithreaded.outputs.flags }} \ - -m "not slow or slow" - - if: matrix.coverage-target - uses: codecov/codecov-action@v5 - with: - files: ./coverage.xml - flags: unittests - token: ${{ secrets.CODECOV_TOKEN }} - - uses: actions/upload-artifact@v6 - if: inputs.test-output-path - with: - name: test-output-${{ matrix.runs-on }}-${{ matrix.python-version }} - path: ${{ inputs.test-output-path }} diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 32c6579c..67334ee7 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -9,7 +9,7 @@ on: jobs: update_release_draft: - runs-on: ubuntu-24.04 + runs-on: ubuntu-slim steps: - uses: release-drafter/release-drafter@v6 env: diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 00000000..705796c5 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,96 @@ +env: + FORCE_COLOR: "1" + PYTHONHASHSEED: "0" + +on: + workflow_call: + inputs: + coverage-python-version: + default: "" + required: false + type: string + macos-python-version: + required: false + type: string + multithreaded: + default: true + required: false + type: boolean + skipped-python-versions: + required: false + type: string + test-output-path: + required: false + type: string + secrets: + CODECOV_TOKEN: + description: Token for uploading reports to Codecov. See https://docs.codecov.com/docs/codecov-uploader. + required: false + +jobs: + create-matrix: + name: Determine job matrix + outputs: + matrix: ${{ steps.set-matrix.outputs.matrix }} + runs-on: ubuntu-slim + steps: + - id: set-matrix + uses: ComPWA/actions/create-pytest-matrix@v4 + with: + coverage-python-version: ${{ inputs.coverage-python-version }} + macos-python-version: ${{ inputs.macos-python-version }} + skipped-python-versions: ${{ inputs.skipped-python-versions }} + + test: + name: Run unit tests + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + UV_PYTHON: ${{ matrix.python-version }} + needs: create-matrix + runs-on: ${{ matrix.runs-on }} + strategy: + fail-fast: false + matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }} + steps: + - uses: actions/checkout@v6 + - uses: astral-sh/setup-uv@v7 + with: + cache-dependency-glob: | + **/pyproject.toml + **/uv.lock + cache-suffix: test-${{ matrix.python-version }} + - uses: ComPWA/actions/cache-sympy@v4 + - if: inputs.multithreaded + name: Activate pytest multithreading + run: echo "PYTEST_XDIST_WORKER_COUNT=auto" | tee -a $GITHUB_ENV + - id: task-runner + uses: ComPWA/actions/determine-task-runner@v4 + - uses: prefix-dev/setup-pixi@v0.9.4 + if: steps.task-runner.outputs.value == 'pixi' + with: + cache: true + - if: matrix.codecov + run: |- + ${{ case( + steps.task-runner.outputs.value == 'pixi', + 'pixi run cov', + 'uvx --from poethepoet poe cov' + ) }} + - if: ${{ !matrix.codecov }} + run: |- + ${{ case( + steps.task-runner.outputs.value == 'pixi', + 'pixi run test', + 'uvx --from poethepoet poe test' + ) }} + - if: matrix.codecov + uses: codecov/codecov-action@v5 + with: + files: ./coverage.xml + flags: unittests + token: ${{ secrets.CODECOV_TOKEN }} + - uses: actions/upload-artifact@v6 + if: inputs.test-output-path + with: + name: test-output-${{ matrix.runs-on }}-${{ matrix.python-version }} + path: ${{ inputs.test-output-path }} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 453593ee..fee9dab2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -12,22 +12,21 @@ repos: - id: check-useless-excludes - repo: https://github.com/ComPWA/policy - rev: 0.8.0 + rev: 0.8.2rc15 hooks: - id: check-dev-files args: - --allow-deprecated-workflows - - --dependabot=update - --keep-pr-linting + - --keep-workflow=lock.yml - --no-pypi - --no-version-branches - --repo-name=actions - --repo-title=ComPWA actions and shared workflows - --type-checker=ty - - --update-lock-files=no - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.10 + rev: v0.15.0 hooks: - id: ruff-check args: [--fix] @@ -46,7 +45,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/ComPWA/prettier-pre-commit - rev: v3.4.2 + rev: v3.8.1 hooks: - id: prettier @@ -63,7 +62,7 @@ repos: - --in-place - repo: https://github.com/streetsidesoftware/cspell-cli - rev: v9.4.0 + rev: v9.6.0 hooks: - id: cspell @@ -83,7 +82,8 @@ repos: - id: ty name: ty entry: ty check - args: [--output-format=concise] + args: [--no-progress, --output-format=concise] + pass_filenames: false require_serial: true language: system types_or: [python, pyi, jupyter] diff --git a/.vscode/settings.json b/.vscode/settings.json index 2650e2bb..cab8bfa3 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -36,7 +36,6 @@ }, "notebook.formatOnSave.enabled": true, "python.defaultInterpreterPath": ".venv/bin/python", - "python.languageServer": "None", "python.terminal.activateEnvironment": false, "redhat.telemetry.enabled": false, "rewrap.wrappingColumn": 88, diff --git a/README.md b/README.md index 0fb30ed2..2b4da99b 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) [![code style: prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg?style=flat-square)](https://github.com/prettier/prettier) -[![Spelling checked](https://img.shields.io/badge/cspell-checked-brightgreen.svg)](https://github.com/streetsidesoftware/cspell/tree/master/packages/cspell) +[![Spelling checked](https://img.shields.io/badge/cspell-checked-brightgreen.svg)](https://github.com/streetsidesoftware/cspell/tree/main/packages/cspell) [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/charliermarsh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff) [![uv](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json)](https://github.com/astral-sh/uv) [![ty](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ty/main/assets/badge/v0.json)](https://github.com/astral-sh/ty) diff --git a/build-pypi-distribution/action.yml b/build-pypi-distribution/action.yml index 8eafcc6e..51c42c0f 100644 --- a/build-pypi-distribution/action.yml +++ b/build-pypi-distribution/action.yml @@ -9,11 +9,11 @@ description: >- runs: using: composite steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 with: enable-cache: false - run: uv pip install --color=always --system build diff --git a/create-pytest-matrix/action.yml b/create-pytest-matrix/action.yml index 1cb4d398..01194fe2 100644 --- a/create-pytest-matrix/action.yml +++ b/create-pytest-matrix/action.yml @@ -1,41 +1,34 @@ name: Create run matrix of python versions -description: >- - Create a run matrix of python versions for pytest workflow. +description: Create a run matrix of python versions for pytest workflow. inputs: coverage-python-version: - default: "3.13" - description: Python version on which to run the test coverage job. - required: false - coverage-target: - description: >- - Name of the package over which to compute test coverage. Leave empty if - you do not want to compute test coverage. + description: + Python version on which to run the test coverage job. Leave empty to + skip creating a coverage job. required: false macos-python-version: - description: >- + description: Run tests on macOS on a specific version of Python. If left empty, the no macOS job will be created. required: false skipped-python-versions: - description: >- - Do not run tests on the following supported Python versions. + description: Do not run tests on the following supported Python versions. required: false outputs: matrix: - description: >- - A JSON object that can be used for setting `jobs..strategy`. + description: A JSON object that can be used for setting `jobs..strategy`. value: ${{ steps.set-matrix.outputs.matrix }} runs: using: composite steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 with: enable-cache: false - env: @@ -46,10 +39,9 @@ runs: delimiter="$(openssl rand -hex 8)" echo "matrix<<${delimiter}" >> $GITHUB_OUTPUT uv run -p3.13 $GITHUB_ACTION_PATH/main.py \ - '${{ inputs.coverage-python-version }}' \ - '${{ inputs.coverage-target }}' \ - '${{ inputs.macos-python-version }}' \ - '${{ inputs.skipped-python-versions }}' \ + --coverage-python-version=${{ inputs.coverage-python-version }} \ + --macos-python-version=${{ inputs.macos-python-version }} \ + --skipped-python-versions='${{ inputs.skipped-python-versions }}' \ | tee -a $GITHUB_OUTPUT echo "${delimiter}" >> $GITHUB_OUTPUT shell: bash diff --git a/create-pytest-matrix/main.py b/create-pytest-matrix/main.py index 76100199..263a217e 100644 --- a/create-pytest-matrix/main.py +++ b/create-pytest-matrix/main.py @@ -13,7 +13,7 @@ import tomllib from argparse import ArgumentParser from dataclasses import dataclass -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Literal from packaging.specifiers import SpecifierSet from packaging.version import Version @@ -21,37 +21,42 @@ if TYPE_CHECKING: from collections.abc import Sequence +PYTHON_VERSION = Literal[ + "3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14" +] + def main(argv: Sequence[str] | None = None) -> int: parser = ArgumentParser(__doc__) - parser.add_argument("coverage-python-version") - parser.add_argument("coverage-target") - parser.add_argument("macos-python-version") - parser.add_argument("skipped-python-versions") + parser.add_argument( + "--coverage-python-version", choices=[*PYTHON_VERSION.__args__, ""] + ) + parser.add_argument( + "--macos-python-version", choices=[*PYTHON_VERSION.__args__, ""] + ) + parser.add_argument("--skipped-python-versions", type=str) args = parser.parse_args(argv) matrix = create_job_matrix( - args.__dict__["coverage-python-version"], - args.__dict__["coverage-target"], - args.__dict__["macos-python-version"], - _format_skipped_version(args.__dict__["skipped-python-versions"]), + args.coverage_python_version, + args.macos_python_version, + _format_skipped_version(args.skipped_python_versions), ) print(json.dumps(matrix, indent=2)) return 0 -def _format_skipped_version(skipped_python_versions: str) -> set[str] | None: +def _format_skipped_version(skipped_python_versions: str) -> set[PYTHON_VERSION] | None: if skipped_python_versions == "all": return None if not skipped_python_versions: return set() - return set(skipped_python_versions.split(" ")) + return set(skipped_python_versions.split(" ")) # ty:ignore[invalid-return-type] def create_job_matrix( - coverage_python_version: str, - coverage_target: str, - macos_python_version: str, - skipped_python_versions: set[str] | None, + coverage_python_version: PYTHON_VERSION | Literal[""], + macos_python_version: PYTHON_VERSION | Literal[""], + skipped_python_versions: set[PYTHON_VERSION] | None, ) -> dict: supported_python_versions = get_supported_python_versions() if skipped_python_versions is None: @@ -60,7 +65,7 @@ def create_job_matrix( python_versions = sorted( set(supported_python_versions) - skipped_python_versions ) - if coverage_target: + if coverage_python_version: _is_version_allowed(coverage_python_version, supported_python_versions) if coverage_python_version in python_versions: python_versions.remove(coverage_python_version) @@ -77,9 +82,9 @@ def create_job_matrix( "python-version": "3.7", "runs-on": "ubuntu-22.04", }) - if coverage_target: + if coverage_python_version: includes.append({ - "coverage-target": coverage_target, + "codecov": "codecov", "python-version": coverage_python_version, "runs-on": "ubuntu-24.04", }) @@ -100,7 +105,9 @@ def create_job_matrix( return matrix -def _is_version_allowed(version: str, supported_versions: list[str]) -> None: +def _is_version_allowed( + version: PYTHON_VERSION, supported_versions: list[PYTHON_VERSION] +) -> None: if version not in supported_versions: supported_versions_str = ", ".join(supported_versions) msg = f"Selected Python {version}, but the package only supports Python {supported_versions_str}" @@ -111,7 +118,7 @@ def _is_version_allowed(version: str, supported_versions: list[str]) -> None: VERSION_IDENTIFIER = "Programming Language :: Python :: 3." -def get_supported_python_versions() -> list[str]: +def get_supported_python_versions() -> list[PYTHON_VERSION]: version_info = _get_version_info() return _determine_python_versions(version_info) @@ -136,7 +143,7 @@ def _get_version_info() -> VersionInfo: ) -def _determine_python_versions(version_info: VersionInfo) -> list[str]: +def _determine_python_versions(version_info: VersionInfo) -> list[PYTHON_VERSION]: supported_versions = _determine_python_versions_from_classifiers(version_info) if supported_versions is not None: return supported_versions @@ -148,7 +155,7 @@ def _determine_python_versions(version_info: VersionInfo) -> list[str]: def _determine_python_versions_from_classifiers( version_info: VersionInfo, -) -> list[str] | None: +) -> list[PYTHON_VERSION] | None: if version_info.classifiers is None: return None version_identifier = "Programming Language :: Python :: 3." @@ -156,10 +163,10 @@ def _determine_python_versions_from_classifiers( if not versions: return None prefix = version_identifier[:-2] - return [s.replace(prefix, "") for s in versions] + return [s.replace(prefix, "") for s in versions] # ty:ignore[invalid-return-type] -def __get_allowed_versions(version_range: str) -> list[str]: +def __get_allowed_versions(version_range: str) -> list[PYTHON_VERSION]: """Get a list of allowed versions from a version range specifier. >>> __get_allowed_versions(">=3.9,<3.13") @@ -168,7 +175,7 @@ def __get_allowed_versions(version_range: str) -> list[str]: specifier = SpecifierSet(version_range) allowed_versions = [f"3.{v}" for v in range(6, 15)] versions_to_check = [Version(v) for v in sorted(allowed_versions)] - return [str(v) for v in versions_to_check if v in specifier] + return [str(v) for v in versions_to_check if v in specifier] # ty:ignore[invalid-return-type] if __name__ == "__main__": diff --git a/create-python-version-matrix/action.yml b/create-python-version-matrix/action.yml index b4a7b214..1018aaef 100644 --- a/create-python-version-matrix/action.yml +++ b/create-python-version-matrix/action.yml @@ -7,11 +7,6 @@ inputs: default: "3.13" description: Python version on which to run the test coverage job. required: false - coverage-target: - description: >- - Name of the package over which to compute test coverage. Leave empty if - you do not want to compute test coverage. - required: false macos-python-version: description: >- Run tests on macOS on a specific version of Python. If left empty, the no @@ -27,13 +22,13 @@ outputs: runs: using: composite steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - if: hashFiles('pyproject.toml') - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: "3.13" - if: hashFiles('pyproject.toml') - uses: astral-sh/setup-uv@v6 + uses: astral-sh/setup-uv@v7 with: enable-cache: false - env: diff --git a/determine-task-runner/action.yml b/determine-task-runner/action.yml index 496af04d..ae122f7c 100644 --- a/determine-task-runner/action.yml +++ b/determine-task-runner/action.yml @@ -9,11 +9,11 @@ outputs: runs: using: composite steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 with: enable-cache: false - env: diff --git a/get-pypi-name/action.yml b/get-pypi-name/action.yml index 9c3fe3e1..d6a41c39 100644 --- a/get-pypi-name/action.yml +++ b/get-pypi-name/action.yml @@ -10,8 +10,8 @@ outputs: runs: using: composite steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 + - uses: actions/checkout@v6 + - uses: actions/setup-python@v6 with: python-version: "3.13" - id: determine-name diff --git a/get-skipped-pre-commit-hooks/action.yml b/get-skipped-pre-commit-hooks/action.yml index 82dc8d04..94567561 100644 --- a/get-skipped-pre-commit-hooks/action.yml +++ b/get-skipped-pre-commit-hooks/action.yml @@ -14,13 +14,13 @@ outputs: runs: using: composite steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 with: sparse-checkout: .pre-commit-config.yaml - - uses: actions/setup-python@v5 + - uses: actions/setup-python@v6 with: python-version: "3.13" - - uses: astral-sh/setup-uv@v6 + - uses: astral-sh/setup-uv@v7 with: enable-cache: false - env: diff --git a/pip-install/action.yml b/pip-install/action.yml index 42d6ff4f..7b2d554b 100644 --- a/pip-install/action.yml +++ b/pip-install/action.yml @@ -25,7 +25,7 @@ runs: using: composite steps: - if: inputs.python-version - uses: actions/setup-python@v5 + uses: actions/setup-python@v6 with: python-version: ${{ inputs.python-version }} - name: Determine Python version diff --git a/pyproject.toml b/pyproject.toml index b3e1dac5..0d0f0c5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -78,6 +78,7 @@ ignore = [ "PLW1514", "PT001", "PTH", + "RUF067", "SIM108", "T201", ] @@ -106,4 +107,3 @@ trailing_comma_inline_array = true division-by-zero = "warn" possibly-missing-import = "warn" possibly-unresolved-reference = "warn" -unused-ignore-comment = "warn" diff --git a/run-pre-commit/action.yml b/run-pre-commit/action.yml deleted file mode 100644 index 62f3bdd9..00000000 --- a/run-pre-commit/action.yml +++ /dev/null @@ -1,19 +0,0 @@ -name: Run pre-commit hooks with style environment -description: >- - Run local pre-commit hooks that may require the installation of a virtual environment. - -outputs: - cmd: - description: >- - The uv run command to use for `pre-commit` - value: ${{ steps.uv-run.outputs.cmd }} - -runs: - using: composite - steps: - - env: - UV_SYSTEM_PYTHON: 1 - id: uv-run - name: Determine skipped hooks - run: echo "cmd=$(uv run -p3.13 $GITHUB_ACTION_PATH/main.py)" | tee -a $GITHUB_OUTPUT - shell: bash diff --git a/run-pre-commit/main.py b/run-pre-commit/main.py deleted file mode 100644 index e76918e7..00000000 --- a/run-pre-commit/main.py +++ /dev/null @@ -1,42 +0,0 @@ -"""Determine which pre-commit hooks should be skipped.""" - -# /// script -# dependencies = ["rtoml"] -# /// -from pathlib import Path - -import rtoml - - -def main() -> None: - cmd = _get_uv_run_command() - print(cmd) - - -def _get_uv_run_command() -> str: - pyproject_path = Path("pyproject.toml") - if pyproject_path.is_file(): - pyproject = rtoml.load(pyproject_path) - dependency_groups = pyproject.get("dependency-groups") - candidate_groups = [ - "style", - "sty", - "lint", - ] - if dependency_groups is not None: - for group in candidate_groups: - if group in dependency_groups: - return f"uv run --group {group} --no-dev" - project_table = pyproject.get("project", {}) - extras = project_table.get("optional-dependencies") - if extras is not None: - for extra in candidate_groups: - if extra in extras: - return f"uv run --extra {extra} --no-dev" - if "dependencies" in project_table: - return "uv run --no-dev" - return "uvx" - - -if __name__ == "__main__": - raise SystemExit(main())