Speed up CI with uv ⚡

hugovk

Hugo van Kemenade

Posted on November 2, 2024

Speed up CI with uv ⚡

We can use uv to make linting and testing on GitHub Actions around 1.5 times as fast.

Linting

When using pre-commit for linting:

name: Lint

on: [push, pull_request, workflow_dispatch]

env:
  FORCE_COLOR: 1

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
          cache: pip
      - uses: pre-commit/action@v3.0.1
Enter fullscreen mode Exit fullscreen mode

We can replace pre-commit/action with tox-dev/action-pre-commit-uv:

       - uses: actions/setup-python@v5
         with:
           python-version: "3.x"
-          cache: pip
-      - uses: pre-commit/action@v3.0.1
+      - uses: tox-dev/action-pre-commit-uv@v1
Enter fullscreen mode Exit fullscreen mode
name: Lint

on: [push, pull_request, workflow_dispatch]

env:
  FORCE_COLOR: 1

permissions:
  contents: read

jobs:
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false
      - uses: actions/setup-python@v5
        with:
          python-version: "3.x"
      - uses: tox-dev/action-pre-commit-uv@v1
Enter fullscreen mode Exit fullscreen mode

This means uv will create virtual environments and install packages for pre-commit, which is faster for the initial seed operation when there's no cache.

Lint comparison

For example: python/blurb#32

Before After Times faster
No cache 60s 37s 1.62
With cache 11s 11s 1.00

Testing

When testing with tox:

name: Test

on: [push, pull_request, workflow_dispatch]

permissions:
  contents: read

env:
  FORCE_COLOR: 1

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]

    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          allow-prereleases: true
          cache: pip

      - name: Install dependencies
        run: |
          python --version
          python -m pip install -U pip
          python -m pip install -U tox

      - name: Tox tests
        run: |
          tox -e py
Enter fullscreen mode Exit fullscreen mode

We can replace tox with tox-uv:

       - name: Set up Python ${{ matrix.python-version }}
         uses: actions/setup-python@v5
         with:
           python-version: ${{ matrix.python-version }}
           allow-prereleases: true
-          cache: pip

-      - name: Install dependencies
-        run: |
-          python --version
-          python -m pip install -U pip
-          python -m pip install -U tox
+      - name: Install uv
+        uses: hynek/setup-cached-uv@v2

       - name: Tox tests
         run: |
-          tox -e py
+          uvx --with tox-uv tox -e py
Enter fullscreen mode Exit fullscreen mode
name: Test

on: [push, pull_request, workflow_dispatch]

permissions:
  contents: read

env:
  FORCE_COLOR: 1

jobs:
  test:
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"]

    steps:
      - uses: actions/checkout@v4
        with:
          persist-credentials: false

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}
          allow-prereleases: true

      - name: Install uv
        uses: hynek/setup-cached-uv@v2

      - name: Tox tests
        run: |
          uvx --with tox-uv tox -e py
Enter fullscreen mode Exit fullscreen mode

tox-uv is tox plugin to replace virtualenv and pip with uv in your tox environments. We only need to install uv, and use uvx to both install tox-uv and run tox, for faster installs of tox, the virtual environment, and the dependencies within it.

Test comparison

For example: python/blurb#32

Before After Times faster
No cache 2m 0s 1m 26s 1.40
With cache 1m 58s 1m 22s 1.44

No pip with tox-uv

One difference with uv environments compared to regular venv/virtualenv ones is that they do not have pip. This means calls to pip need replacing, for example in tox.ini:

 [testenv]
-commands_pre =
-    {envpython} -m pip install -U -r requirements.txt
+deps =
+    -r requirements.txt
 pass_env =
     FORCE_COLOR
 commands =
     {envpython} -m pytest {posargs}
Enter fullscreen mode Exit fullscreen mode

If you still need pip (or setuptools or wheel), add uv_seed = True to your [testenv] to inject them.

Bonus tip

Run the new tool zizmor to find security issues in GitHub Actions.


Header photo: "Road cycling at the 1952 Helsinki Olympics" by Olympia-Kuva Oy & Helsinki City Museum, Public Domain.

💖 💪 🙅 🚩
hugovk
Hugo van Kemenade

Posted on November 2, 2024

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related

Speed up CI with uv ⚡
python Speed up CI with uv ⚡

November 2, 2024