Repository: wagtail/wagtail-vector-index (language: python)

Issue:
Update tooling
- [x] update linters (black, ruff)
- [x] update tox matrix
- [x] update CI workflows 
  - [x] PyPI Trusted Publishing
  - [x] Coverage



Discussion / hints:

Fix patch:
diff --git a/.coveragerc b/.coveragerc
index 59d7314..c5161e8 100644
--- a/.coveragerc
+++ b/.coveragerc
@@ -1,9 +1,19 @@
 [run]
 branch = True
-include = wagtail_vector_index/*
+parallel = true
+
+source = wagtail_vector_index
 omit = */migrations/*,*/tests/*
 
+[paths]
+source = src, .tox/py*/**/site-packages
+
 [report]
+show_missing = true
+ignore_errors = true
+skip_empty = true
+skip_covered = true
+
 # Regexes for lines to exclude from consideration
 exclude_lines =
     # Have to re-enable the standard pragma
@@ -20,5 +30,3 @@ exclude_lines =
     # Don't complain if non-runnable code isn't run:
     if 0:
     if __name__ == .__main__.:
-
-ignore_errors = True
diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml
index 2a1cd6a..091d282 100644
--- a/.github/workflows/publish.yml
+++ b/.github/workflows/publish.yml
@@ -1,17 +1,14 @@
-# See https://packaging.python.org/en/latest/guides/publishing-package-distribution-releases-using-github-actions-ci-cd-workflows/
-# for a detailed guide
 name: Publish to PyPI
 
 on:
   release:
     types: [published]
 
-permissions:
-  contents: read # to fetch code (actions/checkout)
-
 jobs:
-  build_and_publish:
+  build:
     runs-on: ubuntu-latest
+    permissions:
+      contents: read # to fetch code (actions/checkout)
     steps:
       - uses: actions/checkout@v4
         with:
@@ -22,6 +19,12 @@ jobs:
         with:
           python-version: "3.11"
 
+      - uses: actions/setup-python@v4
+        with:
+          python-version: '3.11'
+          cache: "pip"
+          cache-dependency-path: "**/pyproject.toml"
+
       - name: Install dependencies
         run: |
           python -m pip install --upgrade pip
@@ -31,9 +34,21 @@ jobs:
       - name: Build
         run: python -m flit build
 
-      - name: Publish to PyPI
-        env:
-          FLIT_USERNAME: "__token__"
-          FLIT_PASSWORD: ${{ secrets.PYPI_API_TOKEN }}
-          FLIT_INDEX_URL: https://upload.pypi.org/legacy/
-        run: python -m flit publish
+  # https://docs.pypi.org/trusted-publishers/using-a-publisher/
+  pypi-publish:
+    needs: build
+    environment: 'publish'
+
+    name: Upload release to PyPI
+    runs-on: ubuntu-latest
+    permissions:
+      # Mandatory for trusted publishing
+      id-token: write
+    steps:
+      - uses: actions/download-artifact@v3
+
+      - name: 🚀 Publish package distributions to PyPI
+        uses: pypa/gh-action-pypi-publish@release/v1
+        with:
+          packages-dir: artifact/
+          print-hash: true
diff --git a/.gitignore b/.gitignore
index bb25502..7b46e8e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,6 +6,7 @@ __pycache__/
 /.coverage
 /htmlcov
 /.tox
+/.venv
 /venv
 /.vscode
 /site
@@ -19,3 +20,4 @@ __pycache__/
 devenv.lock
 devenv.nix
 .env
+.ruff_cache
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 52b8549..5a9ee05 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -8,7 +8,7 @@ default_language_version:
 
 repos:
   - repo: https://github.com/pre-commit/pre-commit-hooks
-    rev: v4.4.0
+    rev: v4.5.0
     hooks:
       - id: check-added-large-files
       - id: check-case-conflict
@@ -21,19 +21,16 @@ repos:
       - id: end-of-file-fixer
       - id: trailing-whitespace
   - repo: https://github.com/psf/black-pre-commit-mirror
-    rev: 23.9.1
+    rev: 23.10.1
     hooks:
       - id: black
-        language_version: python3
-        args: ["--target-version", "py37"]
   - repo: https://github.com/adamchainz/blacken-docs
     rev: 1.16.0
     hooks:
       - id: blacken-docs
-        additional_dependencies: [black==23.9.1]
+        additional_dependencies: [black==23.10.1]
   - repo: https://github.com/astral-sh/ruff-pre-commit
-    # Ruff version.
-    rev: v0.0.291
+    rev: v0.1.3
     hooks:
       - id: ruff
         args: [--fix, --exit-non-zero-on-fix]
diff --git a/README.md b/README.md
index c703ae1..a30111b 100644
--- a/README.md
+++ b/README.md
@@ -22,7 +22,9 @@ This provides the backbone for features including:
 
 ## Supported Versions
 
-* Wagtail 4.0, 4.1, 4.2, 5.0, 5.1
+* Wagtail 5.2
+* Django 4.2
+* Python 3.11, 3.12
 
 ## Contributing
 
diff --git a/pyproject.toml b/pyproject.toml
index 2f83f02..0f9fb4c 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -15,29 +15,22 @@ classifiers = [
     "Operating System :: OS Independent",
     "Programming Language :: Python",
     "Programming Language :: Python :: 3",
-    "Programming Language :: Python :: 3.8",
-    "Programming Language :: Python :: 3.9",
-    "Programming Language :: Python :: 3.10",
     "Programming Language :: Python :: 3.11",
+    "Programming Language :: Python :: 3.12",
     "Framework :: Django",
-    "Framework :: Django :: 3.0",
-    "Framework :: Django :: 3.1",
-    "Framework :: Django :: 3.2",
-    "Framework :: Django :: 4.0",
-    "Framework :: Django :: 4.1",
     "Framework :: Django :: 4.2",
     "Framework :: Wagtail",
-    "Framework :: Wagtail :: 4",
     "Framework :: Wagtail :: 5",
 ]
 dynamic = ["version"]
-requires-python = ">=3.8"
+requires-python = ">=3.11"
 dependencies = [
-    "Django>=3.0",
-    "Wagtail>=4.0",
+    "Django>=4.2",
+    "Wagtail>=5.2",
     "tiktoken>=0.3.3",
     "langchain>=0.0.311",
-    "every-ai>=1.1.1"
+    "every-ai>=1.1.1",
+    "aiohttp>=3.9.0b0; python_version >= '3.12'",
 ]
 [project.optional-dependencies]
 numpy = [
@@ -55,7 +48,8 @@ testing = [
     "pytest>=7.4.2",
     "pytest-django>=4.5.2",
     "wagtail-factories>=4.1.0",
-    "factory-boy>=3.3.0"
+    "factory-boy>=3.3.0",
+    "coverage>=7.0,<8.0",
 ]
 docs = [
     "mkdocs>=1.5.3",
@@ -66,17 +60,9 @@ docs = [
 [project.urls]
 Home = "https://github.com/tomusher/wagtail-vector-index"
 
-[tool.ruff]
-select = ["F", "E", "C90", "I", "B", "DJ", "RUF", "TRY", "C4"]
-ignore = ["TRY003", "E501", "RUF012"]
-
 [tool.flit.module]
 name = "wagtail_vector_index"
 
-[tool.pytest.ini_options]
-DJANGO_SETTINGS_MODULE = "testapp.settings"
-pythonpath = ["./", "./tests"]
-
 [tool.flit.sdist]
 include = [
     "wagtail_vector_index/static"
@@ -93,3 +79,11 @@ exclude = [
     "*.ini",
     "*.yml"
 ]
+
+[tool.pytest.ini_options]
+DJANGO_SETTINGS_MODULE = "testapp.settings"
+pythonpath = ["./", "./tests"]
+
+[tool.ruff]
+select = ["F", "E", "C90", "I", "B", "DJ", "RUF", "TRY", "C4"]
+ignore = ["TRY003", "E501", "RUF012"]
diff --git a/setup.cfg b/setup.cfg
deleted file mode 100644
index 6137bb3..0000000
--- a/setup.cfg
+++ /dev/null
@@ -1,14 +0,0 @@
-[flake8]
-max-line-length=88
-exclude=migrations,dist,build,venv,node_modules,.tox,venv,.venv,.git
-# E501: Line too long
-# W503: line break before binary operator (superseded by W504 line break after binary operator)
-ignore = E501,W503
-
-[isort]
-known_first_party=wagtail_vector_index
-skip=migrations,.git,__pycache__,LC_MESSAGES,locale,build,dist,.github,.tox,venv,.venv,node_modules
-blocked_extensions=rst,html,js,svg,txt,css,scss,png,snap,tsx,ts,sh
-lines_between_types=1
-lines_after_imports=2
-profile=black
diff --git a/src/wagtail_vector_index/backends/numpy/backend.py b/src/wagtail_vector_index/backends/numpy/backend.py
index 5f70976..4586c8d 100644
--- a/src/wagtail_vector_index/backends/numpy/backend.py
+++ b/src/wagtail_vector_index/backends/numpy/backend.py
@@ -4,8 +4,8 @@
 
 import numpy as np
 
-from wagtail_vector_index import Document
 from wagtail_vector_index.backends import Backend, Index, SearchResponseDocument
+from wagtail_vector_index.base import Document
 from wagtail_vector_index.index import get_vector_indexes
 
 logger = logging.Logger(__name__)
diff --git a/src/wagtail_vector_index/backends/qdrant/backend.py b/src/wagtail_vector_index/backends/qdrant/backend.py
index d0d8a41..50d4632 100644
--- a/src/wagtail_vector_index/backends/qdrant/backend.py
+++ b/src/wagtail_vector_index/backends/qdrant/backend.py
@@ -3,9 +3,9 @@
 
 from qdrant_client import QdrantClient
 from qdrant_client.http import models as qdrant_models
-from wagail_ai.index import Document
 
 from wagtail_vector_index.backends import Backend, Index, SearchResponseDocument
+from wagtail_vector_index.base import Document
 
 
 @dataclass
diff --git a/tox.ini b/tox.ini
index 8505d3c..26e75e0 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,50 +1,62 @@
 [tox]
+min_version = 4.11
+
 skipsdist = True
-usedevelop = True
 
 envlist =
-    python{3.8,3.9}-django{3.2}-wagtail{4.0,4.1,4.2}-{sqlite,postgres}
-    python{3.10}-django{3.2}-wagtail{4.0,4.1,4.2,main}-{sqlite,postgres}
-    python{3.8,3.9,3.10}-django{4.0}-wagtail{4.0,4.1,4.2,main}-{sqlite,postgres}
-    python{3.8,3.9,3.10,3.11}-django{4.1,main}-wagtail{4.1,4.2,main}-{sqlite,postgres}
-    python{3.8,3.9,3.10,3.11}-django{4.2,main}-wagtail{5.0,5.1,main}-{sqlite,postgres}
+    py{311,312}-django{4.2}-wagtail{5.2}-{sqlite,postgres}
+
+[gh-actions]
+python =
+    3.11: py311
+    3.12: py312
+
+[gh-actions:env]
+DB =
+    sqlite: sqlite
+    postgres: postgres
 
 [testenv]
-commands = pytest {posargs}
+pass_env =
+    FORCE_COLOR
+    NO_COLOR
 
-basepython =
-    python3.8: python3.8
-    python3.9: python3.9
-    python3.10: python3.10
-    python3.11: python3.11
-    python3.12: python3.12
+set_env =
+    PYTHONPATH = {toxinidir}
+    PYTHONDEVMODE = 1
+    postgres: DATABASE_URL={env:DATABASE_URL:postgres:///wagtail_vector_index}
 
 deps =
-    django3.2: Django>=3.2,<4.0
-    django4.0: Django>=4.0,<4.1
-    django4.1: Django>=4.1,<4.2
     django4.2: Django>=4.2,<4.3
-    djangomain: git+https://github.com/django/django.git@main#egg=Django
+    wagtail5.2: wagtail>=5.2,<6.0
+    postgres: psycopg2>=2.9
+    .[testing]
+
+commands = python -Im coverage run -m pytest {posargs}
 
-    wagtail4.0: wagtail>=4.0,<4.1
-    wagtail4.1: wagtail>=4.1,<4.2
-    wagtail4.2: wagtail>=4.2,<4.3
-    wagtail5.0: wagtail>=5.0,<5.1
-    wagtail5.1: wagtail>=5.1,<5.2
-    wagtailmain: git+https://github.com/wagtail/wagtail.git
+[testenv:coverage-report]
+base_python = python3.11
+; a bit of a hack - we want to keep deps to a minimum here
+deps =
+    coverage>=7.0,<8.0
 
-    postgres: psycopg2>=2.6
+commands =
+    python -Im coverage combine
+    python -Im coverage report -m
 
-    .[testing]
+[testenv:wagtailmain]
+description = Test with latest Wagtail main branch
 
-setenv =
-    postgres: DATABASE_URL={env:DATABASE_URL:postgres:///wagtail_vector_index}
+deps =
+    wagtailmain: git+https://github.com/wagtail/wagtail.git@main#egg=Wagtail
 
 [testenv:interactive]
+description = An interactive environment for local testing purposes
+package = editable
 basepython = python3.11
 
 deps =
-    wagtail>=5.1
+    wagtail>=5.2
 
 commands_pre =
     python {toxinidir}/testmanage.py makemigrations


Test patch:
diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index b900e76..e94e678 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -5,7 +5,6 @@ on:
     branches:
       - main
       - 'stable/**'
-      - 'fix-actions'
 
   pull_request:
 
@@ -16,6 +15,13 @@ concurrency:
 permissions:
   contents: read # to fetch code (actions/checkout)
 
+env:
+  FORCE_COLOR: "1" # Make tools pretty.
+  TOX_TESTENV_PASSENV: FORCE_COLOR
+  PIP_DISABLE_PIP_VERSION_CHECK: "1"
+  PIP_NO_PYTHON_VERSION_WARNING: "1"
+  PYTHON_LATEST: "3.12"
+
 jobs:
   lint:
     runs-on: ubuntu-latest
@@ -28,57 +34,44 @@ jobs:
         with:
           python-version: '3.11'
       - uses: pre-commit/action@v3.0.0
-        with:
-          token: ${{ secrets.GITHUB_TOKEN }}
 
   test-sqlite:
     runs-on: ubuntu-latest
     needs: lint
     strategy:
       matrix:
-        python: ['3.8', '3.9']
-        django: ['3.2']
-        wagtail: ['4.1', '4.2']
-        include:
-          - python: '3.10'
-            django: '4.2'
-            wagtail: '5.1'
-          - python: '3.11'
-            django: '4.2'
-            wagtail: '5.1'
-
+        python: ["3.11", "3.12"]
+        db: ["sqlite"]
     steps:
       - uses: actions/checkout@v3
       - name: Set up Python ${{ matrix.python }}
         uses: actions/setup-python@v4
         with:
           python-version: ${{ matrix.python }}
-      - name: Install Tox
+      - name: Install dependencies
         run: |
           python -m pip install --upgrade pip setuptools wheel
-          python -m pip install --upgrade tox
+          python -m pip install --upgrade tox tox-gh-actions
       - name: Test
-        run: |
-          tox
+        run: tox
         env:
-          TOXENV: python${{ matrix.python }}-django${{ matrix.django }}-wagtail${{ matrix.wagtail }}-sqlite
+          DB: sqlite
+
+      - name: Upload coverage data
+        uses: actions/upload-artifact@v3
+        with:
+          name: coverage-data
+          path: .coverage.*
+          if-no-files-found: ignore
+          retention-days: 1
 
   test-postgres:
     runs-on: ubuntu-latest
     needs: lint
     strategy:
       matrix:
-        python: ['3.8', '3.9']
-        django: ['3.2']
-        wagtail: ['4.1', '4.2']
-        experimental: [false]
-        include:
-          - python: '3.10'
-            django: '4.2'
-            wagtail: '5.1'
-          - python: '3.11'
-            django: '4.2'
-            wagtail: '5.1'
+        python: ["3.11", "3.12"]
+        db: ["postgres"]
 
     services:
       postgres:
@@ -100,8 +93,50 @@ jobs:
           python -m pip install --upgrade pip setuptools wheel
           python -m pip install --upgrade tox
       - name: Test
-        run: |
-          tox
+        run: tox
         env:
           DATABASE_URL: postgres://postgres:postgres@localhost:5432/wagtail_vector_index
-          TOXENV: python${{ matrix.python }}-django${{ matrix.django }}-wagtail${{ matrix.wagtail }}-postgres
+          DB: postgres
+      - name: Upload coverage data
+        uses: actions/upload-artifact@v3
+        with:
+          name: coverage-data
+          path: .coverage.*
+          if-no-files-found: ignore
+          retention-days: 1
+
+  coverage:
+    runs-on: ubuntu-latest
+    needs:
+      - test-sqlite
+      - test-postgres
+
+    steps:
+      - uses: actions/checkout@v4
+        with:
+          fetch-depth: 0
+      - uses: actions/setup-python@v4
+        with:
+          # Use latest Python, so it understands all syntax.
+          python-version: ${{env.PYTHON_LATEST}}
+
+      - run: python -Im pip install --upgrade coverage
+
+      - name: Download coverage data
+        uses: actions/download-artifact@v3
+        with:
+          name: coverage-data
+
+      - name: Combine coverage
+        run: |
+          python -Im coverage combine
+          python -Im coverage html --skip-covered --skip-empty
+          python -Im coverage report
+          echo "## Coverage summary" >> $GITHUB_STEP_SUMMARY
+          python -Im coverage report --format=markdown >> $GITHUB_STEP_SUMMARY
+
+      - name: Upload HTML report if check failed.
+        uses: actions/upload-artifact@v3
+        with:
+          name: html-report
+          path: htmlcov