Repository: kraken-tech/django-integrity (language: python)

Issue:
Use `uv` for installing requirements
It's a whole lot faster, and should speed up our test-run.


Discussion / hints:

Fix patch:
diff --git a/.github/workflows/checks.yaml b/.github/workflows/checks.yaml
index ac9a110..a9a602b 100644
--- a/.github/workflows/checks.yaml
+++ b/.github/workflows/checks.yaml
@@ -25,8 +25,15 @@ jobs:
             requirements/*.txt
             tox.ini
 
+      - name: Make a virtualenv
+        run: python3 -m venv .venv
+
       - name: Install requirements
-        run: make install
+        run: |
+          source .venv/bin/activate
+          make install
 
       - name: Run linters
-        run: make lint
+        run: |
+          source .venv/bin/activate
+          make lint
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e9daf10..0becb48 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
 - Fix some more incorrect type signatures:
     - `django_integrity.conversion.Unique.fields` was erroneously `tuple[str]` instead of `tuple[str, ...]`.
 - Protect against previously-unhandled potential `None` in errors from Psycopg.
+- Install CI and development requirements with `uv` instead of `pip-tools`.
 
 ## v0.1.1 - 2024-05-09
 
diff --git a/makefile b/makefile
index 8e231c4..b9ad98e 100644
--- a/makefile
+++ b/makefile
@@ -27,20 +27,20 @@ lint:
 
 .PHONY:update
 update:
-	pip-compile pyproject.toml \
+	uv pip compile pyproject.toml \
 		--quiet --upgrade --resolver=backtracking --strip-extras \
 		--extra=dev \
 		--output-file=requirements/development.txt
-	pip-compile pyproject.toml \
+	uv pip compile pyproject.toml \
 		--quiet --upgrade --resolver=backtracking --strip-extras \
 		--extra=pytest-in-tox \
 		--output-file=requirements/pytest-in-tox.txt \
 		--unsafe-package django
-	pip-compile pyproject.toml \
+	uv pip compile pyproject.toml \
 		--quiet --upgrade --resolver=backtracking --strip-extras \
 		--extra=release \
 		--output-file=requirements/release.txt
-	pip-compile pyproject.toml \
+	uv pip compile pyproject.toml \
 		--quiet --upgrade --resolver=backtracking --strip-extras \
 		--extra=tox \
 		--output-file=requirements/tox.txt
@@ -52,7 +52,7 @@ update:
 # Pip install all required Python packages
 .PHONY:install_python_packages
 install_python_packages: install_prerequisites requirements/development.txt
-	pip-sync requirements/development.txt
+	uv pip sync requirements/development.txt
 
 .PHONY:install_prerequisites
 install_prerequisites: requirements/prerequisites.txt
@@ -64,7 +64,7 @@ install_pre_commit:
 
 # Add new dependencies to requirements/development.txt whenever pyproject.toml changes
 requirements/development.txt: pyproject.toml
-	pip-compile pyproject.toml \
+	uv pip compile pyproject.toml \
 		--quiet --resolver=backtracking --strip-extras \
 		--extra=dev \
 		--output-file=requirements/development.txt
diff --git a/pyproject.toml b/pyproject.toml
index b368ba1..6ae176b 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -55,42 +55,43 @@ pytest-in-tox = [
     # We deliberately exclude Django and Psycopg from this list because
     # this groups is used for running the pytest tests with tox,
     # and those packages are a part of tox's test matrix.
-    "dj-database-url",
-    "django-stubs",
-    "environs",
-    "pytest",
-    "pytest-django",
+    "dj-database-url>=2.1.0",
+    "django-stubs>=5.0.0",
+    "environs>=11.0.0",
+    "pytest-django>=4.8.0",
+    "pytest>=8.2.0",
 ]
 release = [
-    "rich",
+    "rich>=13.7.1",
     "tomli >= 1.1.0 ; python_version < '3.11'",
-    "typer",
+    "typer>=0.12.3",
 ]
 tox = [
-    "tox",
+    "tox-uv>=1.8.2",
+    "tox>=4.15.0",
 ]
 dev = [
     # Testing
-    "dj-database-url",
-    "django",
-    "django-stubs",
-    "environs",
-    "psycopg2-binary",
-    "psycopg[binary]",
-    "pytest",
-    "pytest-django",
-    "tox",
-    "types-psycopg2",
+    "dj-database-url>=2.1.0",
+    "django>=4.2.0",
+    "django-stubs>=5.0.0",
+    "environs>=11.0.0",
+    "psycopg2-binary>=2.9.9",
+    "psycopg[binary]>=3.1.18",
+    "pytest-django>=4.8.0",
+    "pytest>=8.2.0",
+    "tox>=4.15.0",
+    "types-psycopg2>=2.9.21.20240417",
 
     # Linting
-    "mypy",
-    "mypy-json-report",
-    "pre-commit",
+    "mypy>=1.10.0",
+    "mypy-json-report>=1.2.0",
+    "pre-commit>=3.7.0",
 
     # CLI utils
-    "rich",
+    "rich>=13.7.1",
     "tomli >= 1.1.0 ; python_version < '3.11'",
-    "typer",
+    "typer>=0.12.3",
 ]
 
 # Ruff
diff --git a/requirements/development.txt b/requirements/development.txt
index 74b48fb..a45b17b 100644
--- a/requirements/development.txt
+++ b/requirements/development.txt
@@ -1,9 +1,5 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-#    pip-compile --extra=dev --output-file=requirements/development.txt --strip-extras pyproject.toml
-#
+# This file was autogenerated by uv via the following command:
+#    uv pip compile pyproject.toml --resolver=backtracking --strip-extras --extra=dev --output-file=requirements/development.txt
 asgiref==3.8.1
     # via
     #   django
@@ -21,19 +17,15 @@ colorama==0.4.6
 distlib==0.3.8
     # via virtualenv
 dj-database-url==2.1.0
-    # via django_integrity (pyproject.toml)
 django==5.0.6
     # via
     #   dj-database-url
     #   django-stubs
     #   django-stubs-ext
-    #   django_integrity (pyproject.toml)
 django-stubs==5.0.0
-    # via django_integrity (pyproject.toml)
 django-stubs-ext==5.0.0
     # via django-stubs
 environs==11.0.0
-    # via django_integrity (pyproject.toml)
 exceptiongroup==1.2.1
     # via pytest
 filelock==3.14.0
@@ -51,11 +43,9 @@ marshmallow==3.21.2
 mdurl==0.1.2
     # via markdown-it-py
 mypy==1.10.0
-    # via django_integrity (pyproject.toml)
 mypy-extensions==1.0.0
     # via mypy
 mypy-json-report==1.2.0
-    # via django_integrity (pyproject.toml)
 nodeenv==1.8.0
     # via pre-commit
 packaging==24.0
@@ -73,49 +63,39 @@ pluggy==1.5.0
     #   pytest
     #   tox
 pre-commit==3.7.0
-    # via django_integrity (pyproject.toml)
 psycopg==3.1.18
-    # via django_integrity (pyproject.toml)
 psycopg-binary==3.1.18
     # via psycopg
 psycopg2-binary==2.9.9
-    # via django_integrity (pyproject.toml)
 pygments==2.18.0
     # via rich
 pyproject-api==1.6.1
     # via tox
 pytest==8.2.0
-    # via
-    #   django_integrity (pyproject.toml)
-    #   pytest-django
+    # via pytest-django
 pytest-django==4.8.0
-    # via django_integrity (pyproject.toml)
 python-dotenv==1.0.1
     # via environs
 pyyaml==6.0.1
     # via pre-commit
 rich==13.7.1
-    # via
-    #   django_integrity (pyproject.toml)
-    #   typer
+    # via typer
+setuptools==69.5.1
+    # via nodeenv
 shellingham==1.5.4
     # via typer
 sqlparse==0.5.0
     # via django
-tomli==2.0.1 ; python_version < "3.11"
+tomli==2.0.1
     # via
     #   django-stubs
-    #   django_integrity (pyproject.toml)
     #   mypy
     #   pyproject-api
     #   pytest
     #   tox
 tox==4.15.0
-    # via django_integrity (pyproject.toml)
 typer==0.12.3
-    # via django_integrity (pyproject.toml)
 types-psycopg2==2.9.21.20240417
-    # via django_integrity (pyproject.toml)
 types-pyyaml==6.0.12.20240311
     # via django-stubs
 typing-extensions==4.11.0
@@ -131,6 +111,3 @@ virtualenv==20.26.1
     # via
     #   pre-commit
     #   tox
-
-# The following packages are considered to be unsafe in a requirements file:
-# setuptools
diff --git a/requirements/prerequisites.txt b/requirements/prerequisites.txt
index 3f62150..8e74d5a 100644
--- a/requirements/prerequisites.txt
+++ b/requirements/prerequisites.txt
@@ -1,2 +1,2 @@
 pip==24.0.0
-pip-tools==7.3.0
+uv==0.1.40
diff --git a/requirements/release.txt b/requirements/release.txt
index a0b190b..a343bb8 100644
--- a/requirements/release.txt
+++ b/requirements/release.txt
@@ -1,9 +1,5 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-#    pip-compile --extra=release --output-file=requirements/release.txt --strip-extras pyproject.toml
-#
+# This file was autogenerated by uv via the following command:
+#    uv pip compile pyproject.toml --resolver=backtracking --strip-extras --extra=release --output-file=requirements/release.txt
 click==8.1.7
     # via typer
 markdown-it-py==3.0.0
@@ -13,14 +9,10 @@ mdurl==0.1.2
 pygments==2.18.0
     # via rich
 rich==13.7.1
-    # via
-    #   django_integrity (pyproject.toml)
-    #   typer
+    # via typer
 shellingham==1.5.4
     # via typer
-tomli==2.0.1 ; python_version < "3.11"
-    # via django_integrity (pyproject.toml)
+tomli==2.0.1
 typer==0.12.3
-    # via django_integrity (pyproject.toml)
 typing-extensions==4.11.0
     # via typer
diff --git a/requirements/tox.txt b/requirements/tox.txt
index 9ace440..a40aa5d 100644
--- a/requirements/tox.txt
+++ b/requirements/tox.txt
@@ -1,9 +1,5 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-#    pip-compile --extra=tox --output-file=requirements/tox.txt --strip-extras pyproject.toml
-#
+# This file was autogenerated by uv via the following command:
+#    uv pip compile pyproject.toml --resolver=backtracking --strip-extras --extra=tox --output-file=requirements/tox.txt
 cachetools==5.3.3
     # via tox
 chardet==5.2.0
@@ -20,6 +16,7 @@ packaging==24.0
     # via
     #   pyproject-api
     #   tox
+    #   tox-uv
 platformdirs==4.2.1
     # via
     #   tox
@@ -33,6 +30,9 @@ tomli==2.0.1
     #   pyproject-api
     #   tox
 tox==4.15.0
-    # via django_integrity (pyproject.toml)
+    # via tox-uv
+tox-uv==1.8.2
+uv==0.1.42
+    # via tox-uv
 virtualenv==20.26.1
     # via tox


Test patch:
diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml
index 501252a..828b0b2 100644
--- a/.github/workflows/tests.yaml
+++ b/.github/workflows/tests.yaml
@@ -50,10 +50,18 @@ jobs:
             requirements/*.txt
             tox.ini
 
-      - name: Install tox
-        run: pip install -r requirements/tox.txt
+      - name: Make a virtualenv
+        run: python3 -m venv .venv
+
+      - name: Install requirements
+        run: |
+          source .venv/bin/activate
+          pip install --requirement requirements/prerequisites.txt
+          uv pip install --requirement requirements/tox.txt
 
       - name: Run the tests
-        run: tox --parallel --parallel-no-spinner --skip-missing-interpreters=false
+        run: |
+          source .venv/bin/activate
+          tox --parallel --parallel-no-spinner --skip-missing-interpreters=false
         env:
           DATABASE_URL: postgres://postgres:postgres@localhost/django_integrity
diff --git a/requirements/pytest-in-tox.txt b/requirements/pytest-in-tox.txt
index f8653c0..3893eea 100644
--- a/requirements/pytest-in-tox.txt
+++ b/requirements/pytest-in-tox.txt
@@ -1,21 +1,14 @@
-#
-# This file is autogenerated by pip-compile with Python 3.10
-# by the following command:
-#
-#    pip-compile --extra=pytest-in-tox --output-file=requirements/pytest-in-tox.txt --strip-extras --unsafe-package=django pyproject.toml
-#
+# This file was autogenerated by uv via the following command:
+#    uv pip compile pyproject.toml --resolver=backtracking --strip-extras --extra=pytest-in-tox --output-file=requirements/pytest-in-tox.txt --unsafe-package django
 asgiref==3.8.1
     # via
     #   django
     #   django-stubs
 dj-database-url==2.1.0
-    # via django_integrity (pyproject.toml)
 django-stubs==5.0.0
-    # via django_integrity (pyproject.toml)
 django-stubs-ext==5.0.0
     # via django-stubs
 environs==11.0.0
-    # via django_integrity (pyproject.toml)
 exceptiongroup==1.2.1
     # via pytest
 iniconfig==2.0.0
@@ -29,11 +22,8 @@ packaging==24.0
 pluggy==1.5.0
     # via pytest
 pytest==8.2.0
-    # via
-    #   django_integrity (pyproject.toml)
-    #   pytest-django
+    # via pytest-django
 pytest-django==4.8.0
-    # via django_integrity (pyproject.toml)
 python-dotenv==1.0.1
     # via environs
 sqlparse==0.5.0
@@ -51,5 +41,5 @@ typing-extensions==4.11.0
     #   django-stubs
     #   django-stubs-ext
 
-# The following packages are considered to be unsafe in a requirements file:
+# The following packages were excluded from the output:
 # django