From eb0343ee2f3363a07d8b84624224a1f8251ab19d Mon Sep 17 00:00:00 2001 From: catborise Date: Sat, 7 Nov 2026 20:19:58 +0300 Subject: [PATCH] fix(tests): the parallel test runner works on Python 3.14; CI tests 3.14 Python 3.14 starts processes with forkserver, which Django 5.2's parallel runner does not support: its workers import the tests before django.setup() and fail (AppRegistryNotReady), and `--parallel` without a number falls back to one process. The project's test runner sets the start method to fork, as it was up to 3.13. The production image runs Python 3.14 (Ubuntu 26.04): CI adds it, and the parallel run moves to that leg. Tried on Ubuntu 26.04's Python 3.14: `test --parallel 4` and `--parallel` (8 processes) pass; before, both hung. --- .github/workflows/test.yml | 7 ++++--- README.md | 4 ++-- webvirtcloud/test_runner.py | 12 ++++++++++++ 3 files changed, 18 insertions(+), 5 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9cf3d98e..baaf0b8a 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,7 +18,7 @@ jobs: strategy: fail-fast: false matrix: - python-version: ['3.10', '3.11', '3.12', '3.13'] + python-version: ['3.10', '3.11', '3.12', '3.13', '3.14'] database: [sqlite] include: - python-version: '3.12' @@ -110,9 +110,10 @@ jobs: coverage run manage.py test coverage report --skip-covered - # The project test runner (webvirtcloud/test_runner.py) on one leg + # The project test runner (webvirtcloud/test_runner.py) on the Docker + # image's Python, whose default start method its workers need changed - name: Run Test Suite In Parallel - if: matrix.python-version == '3.13' && matrix.database == 'sqlite' + if: matrix.python-version == '3.14' && matrix.database == 'sqlite' run: python manage.py test --parallel # The per-file report of one leg, to see what a change left untested diff --git a/README.md b/README.md index 86550017..85eb731a 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # WebVirtCloud -###### Python >=3.10 & Django 5.2 LTS (tested on Python 3.10 – 3.13) +###### Python >=3.10 & Django 5.2 LTS (tested on Python 3.10 – 3.14) WebVirtCloud is a **web visualization and management layer** for **libvirt**-based virtualization infrastructure. @@ -65,7 +65,7 @@ WebVirtCloud and `virt-manager`/`virsh` can manage the same libvirt host **concu ## Installation -The installer supports Ubuntu 22.04 / 24.04 / 26.04, Debian 12 / 13, RHEL / Rocky Linux / AlmaLinux / Oracle Linux 10, openEuler 24.03 LTS, openSUSE Leap 15.x / Tumbleweed and SLES 15; the panel runs on a virtual machine, a physical host or a KVM host itself and needs Python 3.10 or newer. CI tests Python 3.10–3.13 on Ubuntu (sqlite, and PostgreSQL on 3.12) and the Docker image; the distro installs are not tested in CI. Pick one of the three ways below, then do the [first login](#first-login). +The installer supports Ubuntu 22.04 / 24.04 / 26.04, Debian 12 / 13, RHEL / Rocky Linux / AlmaLinux / Oracle Linux 10, openEuler 24.03 LTS, openSUSE Leap 15.x / Tumbleweed and SLES 15; the panel runs on a virtual machine, a physical host or a KVM host itself and needs Python 3.10 or newer. CI tests Python 3.10–3.14 on Ubuntu (sqlite, and PostgreSQL on 3.12) and the Docker image; the distro installs are not tested in CI. Pick one of the three ways below, then do the [first login](#first-login). ### Installer diff --git a/webvirtcloud/test_runner.py b/webvirtcloud/test_runner.py index ab28168f..16569001 100644 --- a/webvirtcloud/test_runner.py +++ b/webvirtcloud/test_runner.py @@ -1,12 +1,24 @@ """manage.py test --parallel on the SQLite database in WAL mode.""" import contextlib +import multiprocessing import os import secrets from django.db import connections from django.test.runner import DiscoverRunner +# Python 3.14 starts processes with forkserver on Linux, which Django 5.2's +# parallel runner does not support (a worker imports the tests before +# django.setup(), and --parallel without a number falls back to one process): +# fork there, as up to 3.13; macOS keeps spawn. Set on import: the command +# resolves --parallel while it parses. +if ( + multiprocessing.get_start_method(allow_none=True) is None + and multiprocessing.get_all_start_methods()[0] == "forkserver" +): + multiprocessing.set_start_method("fork") + def remove_wal_files(name): """Django replaces a SQLite test database by its main file only. A run