This is an automated email from the ASF dual-hosted git repository.

jscheffl pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/main by this push:
     new d212f624cf4 Sync default image Python version references (#64994)
d212f624cf4 is described below

commit d212f624cf46f0adf17369c8e2299e4aae992d5e
Author: DaveT1991 <[email protected]>
AuthorDate: Sat Apr 11 05:10:00 2026 -0400

    Sync default image Python version references (#64994)
    
    * Sync default image Python version references
    
    * Fix mypy type error in _read_global_constants_assignment return type
    
    Since ast.literal_eval() returns Any, annotating the private helper as
    returning str | list[str] caused mypy errors in both callers: assigning
    the result to `list[str]` and returning it as `str`. Changing the return
    type to Any (which matches ast.literal_eval) resolves both without
    requiring casts.
    
    * Update scripts/ci/prek/common_prek_utils.py
    
    Co-authored-by: Copilot <[email protected]>
    
    ---------
    
    Co-authored-by: Copilot <[email protected]>
---
 Dockerfile                                         |  2 +-
 Dockerfile.ci                                      |  2 +-
 docker-stack-docs/build-arg-ref.rst                |  2 +-
 .../customizing/add-build-essential-custom.sh      |  2 +-
 .../docker-examples/customizing/custom-sources.sh  |  2 +-
 .../customizing/pypi-dev-runtime-deps.sh           |  2 +-
 .../customizing/pypi-extras-and-deps.sh            |  2 +-
 .../customizing/pypi-selected-version.sh           |  2 +-
 .../restricted/restricted_environments.sh          |  2 +-
 scripts/ci/prek/common_prek_utils.py               | 33 ++++++++++++++++------
 scripts/ci/prek/upgrade_important_versions.py      | 10 +++++--
 scripts/tests/ci/prek/test_common_prek_utils.py    | 14 +++++++++
 12 files changed, 56 insertions(+), 19 deletions(-)

diff --git a/Dockerfile b/Dockerfile
index ba66abccf6b..b3333db0153 100644
--- a/Dockerfile
+++ b/Dockerfile
@@ -51,7 +51,7 @@ ARG AIRFLOW_USER_HOME_DIR=/home/airflow
 ARG AIRFLOW_VERSION="3.2.0"
 
 ARG BASE_IMAGE="debian:bookworm-slim"
-ARG AIRFLOW_PYTHON_VERSION="3.12.13"
+ARG AIRFLOW_PYTHON_VERSION="3.13.13"
 
 # PYTHON_LTO: Controls whether Python is built with Link-Time Optimization 
(LTO).
 #
diff --git a/Dockerfile.ci b/Dockerfile.ci
index 64f866c87b6..cf9f7437dc4 100644
--- a/Dockerfile.ci
+++ b/Dockerfile.ci
@@ -1673,7 +1673,7 @@ ENV DEV_APT_COMMAND=${DEV_APT_COMMAND} \
     ADDITIONAL_DEV_APT_COMMAND=${ADDITIONAL_DEV_APT_COMMAND}
 
 
-ARG AIRFLOW_PYTHON_VERSION="3.12.13"
+ARG AIRFLOW_PYTHON_VERSION="3.13.13"
 ENV AIRFLOW_PYTHON_VERSION=${AIRFLOW_PYTHON_VERSION}
 ENV GOLANG_MAJOR_MINOR_VERSION="1.26.2"
 ENV RUSTUP_HOME="/usr/local/rustup"
diff --git a/docker-stack-docs/build-arg-ref.rst 
b/docker-stack-docs/build-arg-ref.rst
index cfbed5b423d..692b43036f3 100644
--- a/docker-stack-docs/build-arg-ref.rst
+++ b/docker-stack-docs/build-arg-ref.rst
@@ -32,7 +32,7 @@ Those are the most common arguments that you use when you 
want to build a custom
 
+==========================================+===========================================+=============================================+
 | ``AIRFLOW_VERSION``                      | :subst-code:`|airflow-version|`   
        | Version of Airflow.                         |
 
+------------------------------------------+-------------------------------------------+---------------------------------------------+
-| ``AIRFLOW_PYTHON_VERSION``               | ``3.12.13``                       
        | Version of Python.                          |
+| ``AIRFLOW_PYTHON_VERSION``               | ``3.13.13``                       
        | Version of Python.                          |
 
+------------------------------------------+-------------------------------------------+---------------------------------------------+
 | ``AIRFLOW_EXTRAS``                       | (see below the table)             
        | Default extras with which Airflow is        |
 |                                          |                                   
        | installed.                                  |
diff --git 
a/docker-stack-docs/docker-examples/customizing/add-build-essential-custom.sh 
b/docker-stack-docs/docker-examples/customizing/add-build-essential-custom.sh
index 08122186505..712ec11d39e 100755
--- 
a/docker-stack-docs/docker-examples/customizing/add-build-essential-custom.sh
+++ 
b/docker-stack-docs/docker-examples/customizing/add-build-essential-custom.sh
@@ -33,7 +33,7 @@ docker build . \
     --pull \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg ADDITIONAL_PYTHON_DEPS="mpi4py==4.1.1" \
     --build-arg ADDITIONAL_DEV_APT_DEPS="libopenmpi-dev" \
     --build-arg ADDITIONAL_RUNTIME_APT_DEPS="openmpi-common" \
diff --git a/docker-stack-docs/docker-examples/customizing/custom-sources.sh 
b/docker-stack-docs/docker-examples/customizing/custom-sources.sh
index 23adb16ca1c..185fc7a5250 100755
--- a/docker-stack-docs/docker-examples/customizing/custom-sources.sh
+++ b/docker-stack-docs/docker-examples/customizing/custom-sources.sh
@@ -33,7 +33,7 @@ docker build . -f Dockerfile \
     --pull \
     --platform 'linux/amd64' \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
     --build-arg ADDITIONAL_AIRFLOW_EXTRAS="slack,odbc" \
     --build-arg ADDITIONAL_PYTHON_DEPS=" \
diff --git 
a/docker-stack-docs/docker-examples/customizing/pypi-dev-runtime-deps.sh 
b/docker-stack-docs/docker-examples/customizing/pypi-dev-runtime-deps.sh
index aa92f40cdf9..b9104baeef8 100755
--- a/docker-stack-docs/docker-examples/customizing/pypi-dev-runtime-deps.sh
+++ b/docker-stack-docs/docker-examples/customizing/pypi-dev-runtime-deps.sh
@@ -33,7 +33,7 @@ export DOCKER_BUILDKIT=1
 docker build . \
     --pull \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
     --build-arg ADDITIONAL_AIRFLOW_EXTRAS="jdbc" \
     --build-arg ADDITIONAL_PYTHON_DEPS="pandas==2.1.2" \
diff --git 
a/docker-stack-docs/docker-examples/customizing/pypi-extras-and-deps.sh 
b/docker-stack-docs/docker-examples/customizing/pypi-extras-and-deps.sh
index f5a090ebec6..622efcfeaff 100755
--- a/docker-stack-docs/docker-examples/customizing/pypi-extras-and-deps.sh
+++ b/docker-stack-docs/docker-examples/customizing/pypi-extras-and-deps.sh
@@ -32,7 +32,7 @@ export DOCKER_BUILDKIT=1
 docker build . \
     --pull \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
     --build-arg ADDITIONAL_AIRFLOW_EXTRAS="mssql,hdfs" \
     --build-arg ADDITIONAL_PYTHON_DEPS="oauth2client" \
diff --git 
a/docker-stack-docs/docker-examples/customizing/pypi-selected-version.sh 
b/docker-stack-docs/docker-examples/customizing/pypi-selected-version.sh
index 4043291dab9..a68810e79b2 100755
--- a/docker-stack-docs/docker-examples/customizing/pypi-selected-version.sh
+++ b/docker-stack-docs/docker-examples/customizing/pypi-selected-version.sh
@@ -31,7 +31,7 @@ export DOCKER_BUILDKIT=1
 
 docker build . \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
     --tag "my-pypi-selected-version:0.0.1"
 # [END build]
diff --git 
a/docker-stack-docs/docker-examples/restricted/restricted_environments.sh 
b/docker-stack-docs/docker-examples/restricted/restricted_environments.sh
index 443789917a9..43908fb0fd2 100755
--- a/docker-stack-docs/docker-examples/restricted/restricted_environments.sh
+++ b/docker-stack-docs/docker-examples/restricted/restricted_environments.sh
@@ -48,7 +48,7 @@ export DOCKER_BUILDKIT=1
 docker build . \
     --pull \
     --build-arg BASE_IMAGE="debian:bookworm-slim" \
-    --build-arg AIRFLOW_PYTHON_VERSION="3.12.13" \
+    --build-arg AIRFLOW_PYTHON_VERSION="3.13.13" \
     --build-arg AIRFLOW_INSTALLATION_METHOD="apache-airflow" \
     --build-arg AIRFLOW_VERSION="${AIRFLOW_VERSION}" \
     --build-arg INSTALL_MYSQL_CLIENT="false" \
diff --git a/scripts/ci/prek/common_prek_utils.py 
b/scripts/ci/prek/common_prek_utils.py
index 95d9fb61afc..c242396fc65 100644
--- a/scripts/ci/prek/common_prek_utils.py
+++ b/scripts/ci/prek/common_prek_utils.py
@@ -29,6 +29,7 @@ from collections.abc import Generator
 from contextlib import contextmanager
 from pathlib import Path
 from tempfile import NamedTemporaryFile, _TemporaryFileWrapper
+from typing import Any
 
 AIRFLOW_ROOT_PATH = Path(__file__).parents[3].resolve()
 AIRFLOW_CORE_ROOT_PATH = AIRFLOW_ROOT_PATH / "airflow-core"
@@ -118,19 +119,35 @@ GLOBAL_CONSTANTS_PATH = (
 )
 
 
+def _read_global_constants_assignment(name: str) -> Any:
+    """Read a top-level assignment from global_constants.py."""
+    tree = ast.parse(GLOBAL_CONSTANTS_PATH.read_text())
+    for node in tree.body:
+        if isinstance(node, ast.Assign):
+            for target in node.targets:
+                if isinstance(target, ast.Name) and target.id == name:
+                    return ast.literal_eval(node.value)
+    raise RuntimeError(f"{name} not found in global_constants.py")
+
+
 def read_allowed_kubernetes_versions() -> list[str]:
     """Parse ALLOWED_KUBERNETES_VERSIONS from global_constants.py (single 
source of truth).
 
     Returns versions without the ``v`` prefix, e.g. ``["1.30.13", "1.31.12", 
...]``.
     """
-    tree = ast.parse(GLOBAL_CONSTANTS_PATH.read_text())
-    for node in tree.body:
-        if isinstance(node, ast.Assign):
-            for target in node.targets:
-                if isinstance(target, ast.Name) and target.id == 
"ALLOWED_KUBERNETES_VERSIONS":
-                    versions: list[str] = ast.literal_eval(node.value)
-                    return [v.lstrip("v") for v in versions]
-    raise RuntimeError("ALLOWED_KUBERNETES_VERSIONS not found in 
global_constants.py")
+    versions: list[str] = 
_read_global_constants_assignment("ALLOWED_KUBERNETES_VERSIONS")
+    return [v.lstrip("v") for v in versions]
+
+
+def read_default_python_major_minor_version_for_images() -> str:
+    """Parse DEFAULT_PYTHON_MAJOR_MINOR_VERSION_FOR_IMAGES from 
global_constants.py."""
+    value = 
_read_global_constants_assignment("DEFAULT_PYTHON_MAJOR_MINOR_VERSION_FOR_IMAGES")
+    if not isinstance(value, str):
+        raise RuntimeError(
+            "DEFAULT_PYTHON_MAJOR_MINOR_VERSION_FOR_IMAGES in 
global_constants.py "
+            f"must be a string, got {type(value).__name__}"
+        )
+    return value
 
 
 def pre_process_mypy_files(files: list[str]) -> list[str]:
diff --git a/scripts/ci/prek/upgrade_important_versions.py 
b/scripts/ci/prek/upgrade_important_versions.py
index 9d165cc7f84..63975364b80 100755
--- a/scripts/ci/prek/upgrade_important_versions.py
+++ b/scripts/ci/prek/upgrade_important_versions.py
@@ -42,7 +42,13 @@ from enum import Enum
 from pathlib import Path
 
 import requests
-from common_prek_utils import AIRFLOW_CORE_ROOT_PATH, AIRFLOW_ROOT_PATH, 
console, retrieve_gh_token
+from common_prek_utils import (
+    AIRFLOW_CORE_ROOT_PATH,
+    AIRFLOW_ROOT_PATH,
+    console,
+    read_default_python_major_minor_version_for_images,
+    retrieve_gh_token,
+)
 from packaging.version import Version
 
 DOCKER_IMAGES_EXAMPLE_DIR_PATH = AIRFLOW_ROOT_PATH / "docker-stack-docs" / 
"docker-examples"
@@ -490,7 +496,7 @@ UPGRADE_OPENAPI_GENERATOR: bool = 
get_env_bool("UPGRADE_OPENAPI_GENERATOR")
 UPGRADE_SPHINX_AIRFLOW_THEME: bool = 
get_env_bool("UPGRADE_SPHINX_AIRFLOW_THEME")
 
 ALL_PYTHON_MAJOR_MINOR_VERSIONS = ["3.10", "3.11", "3.12", "3.13"]
-DEFAULT_PROD_IMAGE_PYTHON_VERSION = "3.12"
+DEFAULT_PROD_IMAGE_PYTHON_VERSION = 
read_default_python_major_minor_version_for_images()
 
 
 def replace_version(pattern: re.Pattern[str], version: str, text: str, 
keep_total_length: bool = True) -> str:
diff --git a/scripts/tests/ci/prek/test_common_prek_utils.py 
b/scripts/tests/ci/prek/test_common_prek_utils.py
index e6da2f74be0..3ebf6dff400 100644
--- a/scripts/tests/ci/prek/test_common_prek_utils.py
+++ b/scripts/tests/ci/prek/test_common_prek_utils.py
@@ -30,6 +30,7 @@ from ci.prek.common_prek_utils import (
     pre_process_mypy_files,
     read_airflow_version,
     read_allowed_kubernetes_versions,
+    read_default_python_major_minor_version_for_images,
     temporary_tsc_project,
 )
 
@@ -266,6 +267,19 @@ class TestReadAllowedKubernetesVersions:
             assert parts[1].isdigit()
 
 
+class TestReadDefaultPythonMajorMinorVersionForImages:
+    def test_returns_version_string(self):
+        version = read_default_python_major_minor_version_for_images()
+        assert isinstance(version, str)
+
+    def test_version_looks_like_major_minor(self):
+        version = read_default_python_major_minor_version_for_images()
+        parts = version.split(".")
+        assert len(parts) == 2
+        assert parts[0].isdigit()
+        assert parts[1].isdigit()
+
+
 class TestConsoleDiff:
     def test_dump_added_lines(self):
         diff = ConsoleDiff()

Reply via email to