From b09ebcbef6de8a3fce0390d37b9f498e3db36b69 Mon Sep 17 00:00:00 2001 From: dgtlmoon Date: Mon, 2 Mar 2026 11:28:52 +0100 Subject: [PATCH] Python 3.14 CI test and support (#3941) --- .github/workflows/test-only.yml | 11 ++++++- .../test-stack-reusable-workflow.yml | 14 ++++++++- changedetectionio/tests/conftest.py | 29 +++++++++++++++++++ 3 files changed, 52 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test-only.yml b/.github/workflows/test-only.yml index 3de8692b..b2666f10 100644 --- a/.github/workflows/test-only.yml +++ b/.github/workflows/test-only.yml @@ -52,4 +52,13 @@ jobs: uses: ./.github/workflows/test-stack-reusable-workflow.yml with: python-version: '3.13' - skip-pypuppeteer: true \ No newline at end of file + skip-pypuppeteer: true + + + test-application-3-14: + #if: github.event_name == 'push' && github.ref == 'refs/heads/master' + needs: lint-code + uses: ./.github/workflows/test-stack-reusable-workflow.yml + with: + python-version: '3.14' + skip-pypuppeteer: false diff --git a/.github/workflows/test-stack-reusable-workflow.yml b/.github/workflows/test-stack-reusable-workflow.yml index 080247d0..15aabd2b 100644 --- a/.github/workflows/test-stack-reusable-workflow.yml +++ b/.github/workflows/test-stack-reusable-workflow.yml @@ -706,7 +706,19 @@ jobs: - name: Check upgrade works without error run: | echo "=== Testing upgrade path from 0.49.1 to ${{ github.ref_name }} (${{ github.sha }}) ===" - + sudo apt-get update && sudo apt-get install -y --no-install-recommends \ + g++ \ + gcc \ + libc-dev \ + libffi-dev \ + libjpeg-dev \ + libssl-dev \ + libxslt-dev \ + make \ + patch \ + pkg-config \ + zlib1g-dev + # Checkout old version and create datastore git checkout 0.49.1 python3 -m venv .venv diff --git a/changedetectionio/tests/conftest.py b/changedetectionio/tests/conftest.py index 6da101c4..8972ba8e 100644 --- a/changedetectionio/tests/conftest.py +++ b/changedetectionio/tests/conftest.py @@ -2,6 +2,7 @@ import psutil import time from threading import Thread +import multiprocessing import pytest import arrow @@ -191,6 +192,34 @@ def cleanup(datastore_path): if os.path.isfile(f): os.unlink(f) +def pytest_configure(config): + """Configure pytest environment before tests run. + + CRITICAL: Set multiprocessing start method to 'fork' for Python 3.14+ compatibility. + + Python 3.14 changed the default start method from 'fork' to 'forkserver' on Linux. + The forkserver method requires all objects to be picklable, but pytest-flask's + LiveServer uses nested functions that can't be pickled. + + Setting 'fork' explicitly: + - Maintains compatibility with Python 3.10-3.13 (where 'fork' was already default) + - Fixes Python 3.14 pickling errors + - Only affects Unix-like systems (Windows uses 'spawn' regardless) + + See: https://github.com/python/cpython/issues/126831 + See: https://docs.python.org/3/whatsnew/3.14.html + """ + # Only set if not already set (respects existing configuration) + if multiprocessing.get_start_method(allow_none=True) is None: + try: + # 'fork' is available on Unix-like systems (Linux, macOS) + # On Windows, this will have no effect as 'spawn' is the only option + multiprocessing.set_start_method('fork', force=False) + logger.debug("Set multiprocessing start method to 'fork' for Python 3.14+ compatibility") + except (ValueError, RuntimeError): + # Already set, not available on this platform, or context already created + pass + def pytest_addoption(parser): """Add custom command-line options for pytest.