From 7819ad7605d8656242c30789e5bd9deacee1bf42 Mon Sep 17 00:00:00 2001 From: Shanmukh Pawan Date: Wed, 18 Mar 2026 11:21:37 -0400 Subject: [PATCH 1/3] cleanup: drop Python 3.11 support Make Python 3.12 the minimum supported version. Python 3.11 is in security-fix only mode upstream, and downstream (RHEL) has stopped using it. This reduces the CI test matrix and enables use of Python 3.12 features. - Remove Python 3.11 classifier from pyproject.toml and e2e plugins - Bump requires-python from >=3.11 to >=3.12 - Bump ruff target-version from py311 to py312 - Remove 3.11 from CI test matrix (unit + e2e workflows) - Update check, publish, and docs workflows to use Python 3.12 - Remove all 3.11 check-success entries from Mergify config - Update example Containerfile to default to Python 3.12 Closes: #948 Made-with: Cursor Signed-off-by: Shanmukh Pawan --- .github/workflows/check.yaml | 10 +++++----- .github/workflows/python-publish.yaml | 2 +- .github/workflows/test.yaml | 4 ---- .mergify.yml | 9 --------- .readthedocs.yaml | 2 +- docs/example/Containerfile | 2 +- e2e/flit_core_override/pyproject.toml | 3 +-- e2e/fromager_hooks/pyproject.toml | 3 +-- e2e/stevedore_override/pyproject.toml | 3 +-- pyproject.toml | 5 ++--- 10 files changed, 13 insertions(+), 30 deletions(-) diff --git a/.github/workflows/check.yaml b/.github/workflows/check.yaml index 668d3374..7ae0a77a 100644 --- a/.github/workflows/check.yaml +++ b/.github/workflows/check.yaml @@ -18,7 +18,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" # minimum supported lang version + python-version: "3.12" # minimum supported lang version - name: Install dependencies run: python -m pip install hatch 'click!=8.3.0' @@ -39,7 +39,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" # minimum supported lang version + python-version: "3.12" # minimum supported lang version - name: Install dependencies run: python -m pip install hatch 'click!=8.3.0' @@ -60,7 +60,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" # minimum supported lang version + python-version: "3.12" # minimum supported lang version - name: Install dependencies run: python -m pip install hatch 'click!=8.3.0' @@ -81,7 +81,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" # minimum supported lang version + python-version: "3.12" # minimum supported lang version - name: Install dependencies run: python -m pip install hatch 'click!=8.3.0' @@ -118,7 +118,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: "3.11" # minimum supported lang version + python-version: "3.12" # minimum supported lang version - name: Install dependencies run: python -m pip install hatch 'click!=8.3.0' diff --git a/.github/workflows/python-publish.yaml b/.github/workflows/python-publish.yaml index 99030574..b2663803 100644 --- a/.github/workflows/python-publish.yaml +++ b/.github/workflows/python-publish.yaml @@ -25,7 +25,7 @@ jobs: - name: Set up Python uses: actions/setup-python@v6 with: - python-version: '3.11' + python-version: '3.12' - name: Install dependencies run: | python -m pip install --upgrade pip diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index 829ad187..3404f730 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -13,7 +13,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.11" - "3.12" - "3.13" - "3.14" @@ -71,7 +70,6 @@ jobs: fail-fast: false matrix: python-version: - - "3.11" - "3.12" - "3.13" - "3.14" @@ -91,8 +89,6 @@ jobs: exclude: # macOS tests are slower and congested # only run macOS tests on latest stable Python version - - os: macos-latest - python-version: "3.11" - os: macos-latest python-version: "3.12" - os: macos-latest diff --git a/.mergify.yml b/.mergify.yml index 596fb901..76d10090 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -29,8 +29,6 @@ pull_request_rules: - "-draft" # Unit tests - - check-success=unit (3.11, 1.75, ubuntu-latest) - - check-success=unit (3.11, 1.75, macos-latest) - check-success=unit (3.12, 1.75, ubuntu-latest) - check-success=unit (3.12, 1.75, macos-latest) - check-success=unit (3.13, 1.75, ubuntu-latest) @@ -42,13 +40,6 @@ pull_request_rules: - check-success=mypy # E2E test suites (consolidated from individual tests) - # Python 3.11 - Ubuntu only (macOS excluded) - - check-success=e2e (3.11, 1.75, ci_bootstrap_parallel_suite, ubuntu-latest) - - check-success=e2e (3.11, 1.75, ci_bootstrap_suite, ubuntu-latest) - - check-success=e2e (3.11, 1.75, ci_build_suite, ubuntu-latest) - - check-success=e2e (3.11, 1.75, ci_config_suite, ubuntu-latest) - - check-success=e2e (3.11, 1.75, ci_specialized_suite, ubuntu-latest) - - check-success=e2e (3.11, 1.75, ci_workflow_suite, ubuntu-latest) # Python 3.12 - Ubuntu only (macOS excluded) - check-success=e2e (3.12, 1.75, ci_bootstrap_parallel_suite, ubuntu-latest) - check-success=e2e (3.12, 1.75, ci_bootstrap_suite, ubuntu-latest) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index ea385f40..4fc140c7 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -3,7 +3,7 @@ version: 2 build: os: ubuntu-22.04 tools: - python: "3.11" + python: "3.12" sphinx: configuration: docs/conf.py diff --git a/docs/example/Containerfile b/docs/example/Containerfile index e685f4aa..e8910a3d 100644 --- a/docs/example/Containerfile +++ b/docs/example/Containerfile @@ -18,7 +18,7 @@ ENV APP_ROOT=/opt/app-root \ PATH=/opt/app-root/src/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin # Python, pip, and virtual env settings -ARG PYTHON_VERSION=3.11 +ARG PYTHON_VERSION=3.12 ENV PYTHON_VERSION=${PYTHON_VERSION} \ PYTHON=python${PYTHON_VERSION} \ PIP_NO_CACHE_DIR=off \ diff --git a/e2e/flit_core_override/pyproject.toml b/e2e/flit_core_override/pyproject.toml index cbeec0b8..e16a06eb 100644 --- a/e2e/flit_core_override/pyproject.toml +++ b/e2e/flit_core_override/pyproject.toml @@ -16,13 +16,12 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Utilities", ] -requires-python = ">=3.11" +requires-python = ">=3.12" dependencies = [] diff --git a/e2e/fromager_hooks/pyproject.toml b/e2e/fromager_hooks/pyproject.toml index 2391945f..af578e26 100644 --- a/e2e/fromager_hooks/pyproject.toml +++ b/e2e/fromager_hooks/pyproject.toml @@ -16,13 +16,12 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Utilities", ] -requires-python = ">=3.11" +requires-python = ">=3.12" dependencies = [] diff --git a/e2e/stevedore_override/pyproject.toml b/e2e/stevedore_override/pyproject.toml index 54c8a246..25c4598e 100644 --- a/e2e/stevedore_override/pyproject.toml +++ b/e2e/stevedore_override/pyproject.toml @@ -16,13 +16,12 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Utilities", ] -requires-python = ">=3.11" +requires-python = ">=3.12" dependencies = [] diff --git a/pyproject.toml b/pyproject.toml index acc539c8..d25daff6 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -21,7 +21,6 @@ classifiers = [ "Programming Language :: Python", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", "Programming Language :: Python :: 3.14", @@ -29,7 +28,7 @@ classifiers = [ "Topic :: Utilities", ] -requires-python = ">=3.11" +requires-python = ">=3.12" dependencies = [ "click>=8.1.7", @@ -154,7 +153,7 @@ source = "vcs" packages = ["src/fromager"] [tool.ruff] -target-version = "py311" +target-version = "py312" # same as black's default line length line-length = 88 exclude = [ From 5ce3ec4e34a93e5889d8d89fd46d76e59e7c2141 Mon Sep 17 00:00:00 2001 From: Shanmukh Pawan Date: Wed, 18 Mar 2026 13:36:24 -0400 Subject: [PATCH 2/3] refactor: use PEP 695 type keyword for type aliases Replace typing.TypeAlias annotations with the Python 3.12 type statement (PEP 695) in build commands and resolver modules. This was flagged by ruff UP040 after bumping target-version to py312. Co-Authored-By: Claude Signed-off-by: Shanmukh Pawan --- src/fromager/commands/build.py | 6 ++---- src/fromager/resolver.py | 12 +++++------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/src/fromager/commands/build.py b/src/fromager/commands/build.py index dacee2e2..204f01ac 100644 --- a/src/fromager/commands/build.py +++ b/src/fromager/commands/build.py @@ -58,10 +58,8 @@ def dict_factory(x: list[tuple[str, typing.Any]]) -> dict[str, typing.Any]: } -BuildSequenceEntryFuture: typing.TypeAlias = concurrent.futures.Future[ - BuildSequenceEntry -] -DependencyNodeSet: typing.TypeAlias = set[dependency_graph.DependencyNode] +type BuildSequenceEntryFuture = concurrent.futures.Future[BuildSequenceEntry] +type DependencyNodeSet = set[dependency_graph.DependencyNode] @click.command() diff --git a/src/fromager/resolver.py b/src/fromager/resolver.py index 1ab015a8..2fc100b2 100644 --- a/src/fromager/resolver.py +++ b/src/fromager/resolver.py @@ -369,14 +369,12 @@ def get_project_from_pypi( logger.info("ignored all candidate files at %s", sdist_server_url) -RequirementsMap: typing.TypeAlias = typing.Mapping[str, typing.Iterable[Requirement]] -Candidates: typing.TypeAlias = typing.Iterable[Candidate] -CandidatesMap: typing.TypeAlias = typing.Mapping[str, Candidates] +type RequirementsMap = typing.Mapping[str, typing.Iterable[Requirement]] +type Candidates = typing.Iterable[Candidate] +type CandidatesMap = typing.Mapping[str, Candidates] # {identifier: [cls, cachekey]: list[candidates]}} -ResolverCache: typing.TypeAlias = dict[ - str, dict[tuple[type[ExtrasProvider], str], list[Candidate]] -] -VersionSource: typing.TypeAlias = typing.Callable[ +type ResolverCache = dict[str, dict[tuple[type[ExtrasProvider], str], list[Candidate]]] +type VersionSource = typing.Callable[ [str], typing.Iterable[Candidate | tuple[str, str | Version]], ] From 365a96fd591936ea6c381223188e5e691b33470a Mon Sep 17 00:00:00 2001 From: Shanmukh Pawan Date: Wed, 18 Mar 2026 13:58:55 -0400 Subject: [PATCH 3/3] docs: update Python 3.11 references to 3.12 - docs/quickstart.rst: bump prerequisite from 3.11 to 3.12 - CONTRIBUTING.md: bump prerequisite from 3.11 to 3.12 - docs/example/Containerfile: update comment from python-311 to python-312 Made-with: Cursor Signed-off-by: Shanmukh Pawan --- CONTRIBUTING.md | 4 ++-- docs/example/Containerfile | 2 +- docs/quickstart.rst | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index efe85384..4fea8952 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -22,7 +22,7 @@ Fromager thrives on practical, well-tested contributions. This guide summarizes ### Prerequisites -- Python 3.11 or newer +- Python 3.12 or newer - `hatch` for environment and task management ```bash @@ -99,7 +99,7 @@ The pre-commit hook prevents commits that would fail some CI quality checks, sav ### Type Annotations - Every function (including tests) must annotate all parameters and return values. -- Use modern `X | None` syntax instead of `Optional[X]` (requires Python 3.11+). +- Use modern `X | None` syntax instead of `Optional[X]` (PEP 604). - Prefer precise collection types (`list[str]`, `dict[str, int]`, etc.). ```python diff --git a/docs/example/Containerfile b/docs/example/Containerfile index e8910a3d..c415de38 100644 --- a/docs/example/Containerfile +++ b/docs/example/Containerfile @@ -12,7 +12,7 @@ RUN dnf install -y --nodocs \ patch rust cargo \ && dnf clean all -# /opt/app-root structure (same as s2i-core and ubi9/python-311) +# /opt/app-root structure (same as s2i-core and ubi9/python-312) ENV APP_ROOT=/opt/app-root \ HOME=/opt/app-root/src \ PATH=/opt/app-root/src/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin diff --git a/docs/quickstart.rst b/docs/quickstart.rst index 68ba489a..a4ea3228 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -6,7 +6,7 @@ This guide gets you from zero to your first wheel build in under 5 minutes. Prerequisites ------------- -You'll need Python 3.11 or later and network access to download packages from PyPI. +You'll need Python 3.12 or later and network access to download packages from PyPI. Installation ------------