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()