From bea3b659bda9aaeef693dea9a9c1f8cc7b9ad84d Mon Sep 17 00:00:00 2001 From: gilgamezh Date: Thu, 18 Jun 2026 10:11:30 +0200 Subject: [PATCH 1/5] Deprecate Python 3.9, set minimum supported version to 3.10 Python 3.9 reached end-of-life on 2025-10-31. Drop 3.6-3.9 from the declared supported set and make 3.10 the minimum: - setup.py: python_requires '>=3.6' -> '>=3.10'; trim classifiers to 3.10-3.13 (3.13 is already exercised in CI). - tests.yaml: drop 3.8 and 3.9 from the unit-test matrix. - README.rst / man page: update the --python usage examples off 3.9. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/tests.yaml | 2 +- README.rst | 4 ++-- man/fades.1 | 2 +- setup.py | 7 ++----- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index f62c772..4376ab5 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -14,7 +14,7 @@ jobs: strategy: matrix: os: [ubuntu-22.04, ubuntu-24.04, macos-14, macos-15, windows-2022, windows-2025] - python-version: [3.8, 3.9, "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.10", "3.11", "3.12", "3.13"] runs-on: ${{ matrix.os }} steps: diff --git a/README.rst b/README.rst index 4e44b78..55d30ec 100644 --- a/README.rst +++ b/README.rst @@ -239,8 +239,8 @@ be installed in your system, but you can control exactly which one to use. No matter which way you're executing the script (see above), you can pass a ``-p`` or ``--python`` argument, indicating the Python version to -be used just with the number (``3.9``), the whole name (``python3.9``) or -the whole path (``/usr/bin/python3.9``). +be used just with the number (``3.11``), the whole name (``python3.11``) or +the whole path (``/usr/bin/python3.11``). Other detail is the verbosity of *fades* when telling what is doing. By default, *fades* only will use stderr to tell if a virtual environment is being diff --git a/man/fades.1 b/man/fades.1 index 9f09fdc..273ab28 100644 --- a/man/fades.1 +++ b/man/fades.1 @@ -82,7 +82,7 @@ Read the dependencies from a file. Format in each line is the same than dependen .TP .BR -p " " \fIversion\fR ", " --python=\fIversion\fR -Select which Python version to be used; the argument can be just the number (3.9), the whole name (python3.9) or the whole path (/usr/bin/python3.9). Of course, the corresponding version of Python needs to be installed in your system. +Select which Python version to be used; the argument can be just the number (3.11), the whole name (python3.11) or the whole path (/usr/bin/python3.11). Of course, the corresponding version of Python needs to be installed in your system. The dependencies can be indicated in multiple places (in the Python source file, with a comment besides the import, in a \fIrequirements\fRfile, and/or through command line. In case of multiple definitions of the same dependency, command line overrides everything else, and requirements file overrides what is specified in the source code. diff --git a/setup.py b/setup.py index b5ee8fb..737ea0a 100755 --- a/setup.py +++ b/setup.py @@ -106,7 +106,7 @@ def finalize_options(self): install_requires=['setuptools'], tests_require=['logassert', 'pyxdg', 'pyuca', 'pytest', 'flake8', 'pep257', 'rst2html5'], # what unittests require - python_requires='>=3.6', # Minimum Python version supported. + python_requires='>=3.10', # Minimum Python version supported. extras_require={ 'pyxdg': 'pyxdg', 'packaging': 'packaging', @@ -140,13 +140,10 @@ def finalize_options(self): 'Programming Language :: Python', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3 :: Only', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - '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', + 'Programming Language :: Python :: 3.13', 'Programming Language :: Python :: Implementation', 'Programming Language :: Python :: Implementation :: CPython', From eacd707f0ebb26bb33bc80c59fc394573c35e4ed Mon Sep 17 00:00:00 2001 From: gilgamezh Date: Thu, 18 Jun 2026 10:07:40 +0200 Subject: [PATCH 2/5] integtests: drop custom Arch image, provision Python via uv The archlinux job used the custom gilgamezh/archlinux-python39 image only to have an older Python prebuilt for the cross-version test. archlinux:latest already ships the newest CPython, and uv can provide the older interpreter at runtime, so the custom image is no longer needed (nothing to maintain or rebuild). The cross-version target moves from EOL 3.9 to 3.11. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/integtests.yaml | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/.github/workflows/integtests.yaml b/.github/workflows/integtests.yaml index f89169c..2ef75d9 100644 --- a/.github/workflows/integtests.yaml +++ b/.github/workflows/integtests.yaml @@ -11,8 +11,10 @@ jobs: archlinux: runs-on: ubuntu-latest container: - # Use https://github.com/gilgamezh/archlinux-python39 to save the python build time - image: gilgamezh/archlinux-python39:latest + # archlinux:latest ships the newest CPython (rolling release), so this + # job exercises fades against the bleeding-edge Python. An older + # interpreter for the cross-version test is provided via uv at runtime. + image: archlinux:latest volumes: - ${{ github.workspace }}:/fades steps: @@ -22,14 +24,17 @@ jobs: fetch-depth: 0 - name: Install dependencies run: | - pacman -Suy --noconfirm python3 python-packaging - - name: Simple fades run + pacman -Suy --noconfirm python3 python-packaging uv git + - name: Simple fades run (newest Python) run: | cd /fades bin/fades -v -d pytest -x pytest --version - - name: Using a different Python + - name: Using a different (older) Python run: | - python bin/fades -v --python=python3.9 -d pytest -x pytest -v --integtest-pyversion=3.9 tests/integtest.py + cd /fades + uv python install 3.11 + OLD=$(uv python find 3.11) + python bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion=3.11 tests/integtest.py fedora: runs-on: ubuntu-latest From ae1ea77dfb934f2d9612393269b6d81e5af25d87 Mon Sep 17 00:00:00 2001 From: gilgamezh Date: Thu, 18 Jun 2026 10:09:10 +0200 Subject: [PATCH 3/5] integtests: provision Python via uv for fedora, windows and generic jobs Standardize all integration jobs on uv for interpreter provisioning: - fedora: install uv from the distro and use it for the older cross-version target instead of `yum install python3.9`, which no longer resolves in current Fedora repos. Cross-version target moves from EOL 3.9 to 3.11. - native-windows / native-generic: replace actions/setup-python with astral-sh/setup-uv + `uv run`, which provisions both the matrix interpreter and the 3.10 cross-version target without per-OS path juggling. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/integtests.yaml | 56 ++++++++++++------------------- 1 file changed, 21 insertions(+), 35 deletions(-) diff --git a/.github/workflows/integtests.yaml b/.github/workflows/integtests.yaml index 2ef75d9..1a629db 100644 --- a/.github/workflows/integtests.yaml +++ b/.github/workflows/integtests.yaml @@ -49,16 +49,17 @@ jobs: fetch-depth: 0 - name: Install dependencies run: | - yum install --assumeyes python3.13 python-packaging + dnf install --assumeyes python3 python3-packaging uv git - name: Simple fades run run: | cd /fades bin/fades -v -d pytest -x pytest --version - - name: Using a different Python + - name: Using a different (older) Python run: | - yum install --assumeyes python3.9 cd /fades - python3.13 bin/fades -v --python=python3.9 -d pytest -x pytest -v --integtest-pyversion=3.9 tests/integtest.py + uv python install 3.11 + OLD=$(uv python find 3.11) + python3 bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion=3.11 tests/integtest.py native-windows: strategy: @@ -73,28 +74,20 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} - uses: actions/setup-python@v5 - id: matrixpy - with: - python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v5 - - name: Also set up Python 3.10 for cross-Python test - uses: actions/setup-python@v5 - id: otherpy - with: - python-version: "3.10" + - name: Set up Pythons + run: uv python install ${{ matrix.python-version }} 3.10 - - name: Install dependencies - run: | - ${{ steps.matrixpy.outputs.python-path }} -m pip install -U packaging - name: Simple fades run - run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v -d pytest -x pytest --version + run: uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v -d pytest -x pytest --version - name: Using a different Python + shell: bash run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=${{ steps.otherpy.outputs.python-path }} -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + OTHER=$(uv python find 3.10) + uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v --python="$OTHER" -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py native-generic: strategy: @@ -109,24 +102,17 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} - uses: actions/setup-python@v5 - id: matrixpy - with: - python-version: ${{ matrix.python-version }} + - name: Install uv + uses: astral-sh/setup-uv@v5 - - name: Also set up Python 3.10 for cross-Python test - uses: actions/setup-python@v5 - with: - python-version: "3.10" + - name: Set up Pythons + run: uv python install ${{ matrix.python-version }} 3.10 - - name: Install dependencies - run: | - ${{ steps.matrixpy.outputs.python-path }} -m pip install -U packaging - name: Simple fades run - run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v -d pytest -x pytest --version + run: uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v -d pytest -x pytest --version - name: Using a different Python + shell: bash run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=python3.10 -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + OTHER=$(uv python find 3.10) + uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v --python="$OTHER" -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py From 67d791027227f739549a9aaae9db8123ff93003d Mon Sep 17 00:00:00 2001 From: gilgamezh Date: Thu, 18 Jun 2026 10:15:46 +0200 Subject: [PATCH 4/5] integtests: revert native jobs to actions/setup-python `uv run` executes the target command inside an ephemeral venv, and fades refuses to run inside a virtual environment (it is a venv manager itself), so the native-windows and native-generic jobs failed. Those jobs never needed uv: actions/setup-python already provides each matrix interpreter (and the 3.10 cross-version target) cleanly on every OS, without a venv wrapper. Revert them. The archlinux and fedora jobs keep uv: there fades runs under the system Python and uv only supplies the *target* interpreter path via `uv python find`, so no venv wrapping is involved. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/integtests.yaml | 47 ++++++++++++++++++++----------- 1 file changed, 31 insertions(+), 16 deletions(-) diff --git a/.github/workflows/integtests.yaml b/.github/workflows/integtests.yaml index 1a629db..ac1a9d3 100644 --- a/.github/workflows/integtests.yaml +++ b/.github/workflows/integtests.yaml @@ -74,20 +74,28 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install uv - uses: astral-sh/setup-uv@v5 + - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} + uses: actions/setup-python@v5 + id: matrixpy + with: + python-version: ${{ matrix.python-version }} - - name: Set up Pythons - run: uv python install ${{ matrix.python-version }} 3.10 + - name: Also set up Python 3.10 for cross-Python test + uses: actions/setup-python@v5 + id: otherpy + with: + python-version: "3.10" + - name: Install dependencies + run: | + ${{ steps.matrixpy.outputs.python-path }} -m pip install -U packaging - name: Simple fades run - run: uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v -d pytest -x pytest --version + run: | + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v -d pytest -x pytest --version - name: Using a different Python - shell: bash run: | - OTHER=$(uv python find 3.10) - uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v --python="$OTHER" -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=${{ steps.otherpy.outputs.python-path }} -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py native-generic: strategy: @@ -102,17 +110,24 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Install uv - uses: astral-sh/setup-uv@v5 + - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} + uses: actions/setup-python@v5 + id: matrixpy + with: + python-version: ${{ matrix.python-version }} - - name: Set up Pythons - run: uv python install ${{ matrix.python-version }} 3.10 + - name: Also set up Python 3.10 for cross-Python test + uses: actions/setup-python@v5 + with: + python-version: "3.10" + - name: Install dependencies + run: | + ${{ steps.matrixpy.outputs.python-path }} -m pip install -U packaging - name: Simple fades run - run: uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v -d pytest -x pytest --version + run: | + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v -d pytest -x pytest --version - name: Using a different Python - shell: bash run: | - OTHER=$(uv python find 3.10) - uv run --no-project --python ${{ matrix.python-version }} --with packaging -- python bin/fades -v --python="$OTHER" -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=python3.10 -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py From e18283d7ad0c574c4de4aa0bdc0724b6a1d27778 Mon Sep 17 00:00:00 2001 From: gilgamezh Date: Thu, 18 Jun 2026 10:19:47 +0200 Subject: [PATCH 5/5] integtests: derive the cross-version target from setup.py Instead of hardcoding the older Python in each job, add a `min-python` job that reads the minimum supported version from setup.py's `python_requires` and exposes it as an output. Every job consumes that single source of truth: - archlinux / fedora: `uv python install` the minimum, target it for the cross-version run. - native-windows / native-generic: the matrix "oldest" entry and the cross-Python setup-python step both take the minimum from the output. Bumping the supported floor in setup.py now automatically updates the integration tests. Co-Authored-By: Claude Opus 4.8 --- .github/workflows/integtests.yaml | 61 ++++++++++++++++++++++--------- 1 file changed, 43 insertions(+), 18 deletions(-) diff --git a/.github/workflows/integtests.yaml b/.github/workflows/integtests.yaml index ac1a9d3..cd1b305 100644 --- a/.github/workflows/integtests.yaml +++ b/.github/workflows/integtests.yaml @@ -8,7 +8,24 @@ on: jobs: + # Single source of truth: the oldest supported Python is whatever setup.py + # declares in `python_requires`. Every job below derives its cross-version + # target from this output instead of hardcoding a version. + min-python: + runs-on: ubuntu-latest + outputs: + version: ${{ steps.minpy.outputs.version }} + steps: + - uses: actions/checkout@v4 + - name: Read minimum supported Python from setup.py + id: minpy + run: | + version=$(grep python_requires setup.py | grep -oE '[0-9]+\.[0-9]+' | head -1) + echo "Minimum supported Python: $version" + echo "version=$version" >> "$GITHUB_OUTPUT" + archlinux: + needs: min-python runs-on: ubuntu-latest container: # archlinux:latest ships the newest CPython (rolling release), so this @@ -29,14 +46,17 @@ jobs: run: | cd /fades bin/fades -v -d pytest -x pytest --version - - name: Using a different (older) Python + - name: Using the oldest supported Python + env: + OLDEST: ${{ needs.min-python.outputs.version }} run: | cd /fades - uv python install 3.11 - OLD=$(uv python find 3.11) - python bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion=3.11 tests/integtest.py + uv python install "$OLDEST" + OLD=$(uv python find "$OLDEST") + python bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion="$OLDEST" tests/integtest.py fedora: + needs: min-python runs-on: ubuntu-latest container: image: fedora:latest @@ -54,21 +74,24 @@ jobs: run: | cd /fades bin/fades -v -d pytest -x pytest --version - - name: Using a different (older) Python + - name: Using the oldest supported Python + env: + OLDEST: ${{ needs.min-python.outputs.version }} run: | cd /fades - uv python install 3.11 - OLD=$(uv python find 3.11) - python3 bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion=3.11 tests/integtest.py + uv python install "$OLDEST" + OLD=$(uv python find "$OLDEST") + python3 bin/fades -v --python="$OLD" -d pytest -x pytest -v --integtest-pyversion="$OLDEST" tests/integtest.py native-windows: + needs: min-python strategy: matrix: # just a selection otherwise it's too much # - latest OS (left here even if it's only one to simplify upgrading later) - # - oldest and newest Python + # - oldest (from setup.py) and newest Python os: [windows-2025] - python-version: [3.8, "3.13"] + python-version: ["${{ needs.min-python.outputs.version }}", "3.13"] runs-on: ${{ matrix.os }} steps: @@ -80,11 +103,11 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Also set up Python 3.10 for cross-Python test + - name: Also set up the oldest supported Python for cross-Python test uses: actions/setup-python@v5 id: otherpy with: - python-version: "3.10" + python-version: ${{ needs.min-python.outputs.version }} - name: Install dependencies run: | @@ -95,16 +118,17 @@ jobs: - name: Using a different Python run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=${{ steps.otherpy.outputs.python-path }} -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=${{ steps.otherpy.outputs.python-path }} -d pytest -x pytest -v --integtest-pyversion=${{ needs.min-python.outputs.version }} tests/integtest.py native-generic: + needs: min-python strategy: matrix: # just a selection otherwise it's too much # - latest OSes - # - oldest and newest Python + # - oldest (from setup.py) and newest Python os: [ubuntu-24.04, macos-15] - python-version: [3.8, "3.13"] + python-version: ["${{ needs.min-python.outputs.version }}", "3.13"] runs-on: ${{ matrix.os }} steps: @@ -116,10 +140,11 @@ jobs: with: python-version: ${{ matrix.python-version }} - - name: Also set up Python 3.10 for cross-Python test + - name: Also set up the oldest supported Python for cross-Python test uses: actions/setup-python@v5 + id: otherpy with: - python-version: "3.10" + python-version: ${{ needs.min-python.outputs.version }} - name: Install dependencies run: | @@ -130,4 +155,4 @@ jobs: - name: Using a different Python run: | - ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=python3.10 -d pytest -x pytest -v --integtest-pyversion=3.10 tests/integtest.py + ${{ steps.matrixpy.outputs.python-path }} bin/fades -v --python=${{ steps.otherpy.outputs.python-path }} -d pytest -x pytest -v --integtest-pyversion=${{ needs.min-python.outputs.version }} tests/integtest.py