From dafc96e67c73af6efbf1024a85c244b2a46c08db Mon Sep 17 00:00:00 2001 From: Shahar Epstein <60007259+shahar1@users.noreply.github.com> Date: Wed, 7 Oct 2026 00:20:49 +0300 Subject: [PATCH] Apply ruff Python 3.11 fixes to dev tooling, scripts and test suites (#74156) Output of ruff --fix with the py311 target for dev/, scripts/ and the e2e, integration and kubernetes test suites, followed by ruff format where the shorter names let calls fit on one line: timezone.utc becomes datetime.UTC. No behaviour change. Four modules are left out: dev/registry/extract_metadata.py, dev/registry/extract_versions.py and the update_airflow_pyproject_toml and upgrade_dependency_floors prek scripts still fall back to tomli on Python 3.10, so their UTC fixes land together with the removal of that fallback in the requires-python bump. --- .../basic_tests/test_basic_dag_operations.py | 4 +- .../base_remote_log_search_test.py | 6 +-- .../e2e_test_utils/clients.py | 4 +- .../test_go_sdk_concurrent_xcom.py | 4 +- .../go_sdk_tests/test_go_sdk_dag.py | 4 +- .../go_sdk_tests/test_go_sdk_task_state.py | 4 +- .../test_go_sdk_taskflow_binding.py | 4 +- .../test_go_sdk_variable_write.py | 4 +- .../java_sdk_tests/test_java_sdk_dag.py | 4 +- .../openlineage_tests/harness.py | 4 +- .../remote_log_tests/test_remote_logging.py | 4 +- .../ts_sdk_tests/test_ts_sdk_dag.py | 4 +- .../test_xcom_object_storage_backend.py | 4 +- dev/breeze/src/airflow_breeze/utils/github.py | 6 +-- .../airflow_breeze/utils/kubernetes_utils.py | 6 +-- .../src/airflow_breeze/utils/parallel.py | 4 +- dev/breeze/tests/test_set_milestone.py | 40 +++++-------------- dev/registry/extract_connections.py | 4 +- dev/registry/extract_parameters.py | 4 +- .../tests/kubernetes_tests/test_base.py | 6 +-- scripts/ci/analyze_ci_job_durations.py | 4 +- scripts/ci/notify_uv_lock_conflicts.py | 4 +- scripts/ci/prek/upgrade_important_versions.py | 4 +- scripts/ci/slack_notification_state.py | 6 +-- .../update_quarantined_test_status.py | 4 +- .../ci/prek/test_upgrade_dependency_floors.py | 4 +- .../prek/test_upgrade_important_versions.py | 5 ++- .../tests/ci/test_notify_uv_lock_conflicts.py | 16 ++++---- .../test_compute_remaining_test_timeout.py | 4 +- .../tests/task_sdk_tests/jwt_plugin.py | 4 +- .../task_sdk_tests/test_dag_run_operations.py | 6 +-- 31 files changed, 84 insertions(+), 101 deletions(-) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/basic_tests/test_basic_dag_operations.py b/airflow-e2e-tests/tests/airflow_e2e_tests/basic_tests/test_basic_dag_operations.py index 6fc7603fcea..9e8568e5f2e 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/basic_tests/test_basic_dag_operations.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/basic_tests/test_basic_dag_operations.py @@ -16,7 +16,7 @@ # under the License. from __future__ import annotations -from datetime import datetime, timezone +from datetime import UTC, datetime from airflow_e2e_tests.e2e_test_utils.clients import AirflowClient @@ -28,7 +28,7 @@ class TestBasicDagFunctionality: def test_xcom_value(self): resp = self.airflow_client.trigger_dag( - "example_xcom_test", json={"logical_date": datetime.now(timezone.utc).isoformat()} + "example_xcom_test", json={"logical_date": datetime.now(UTC).isoformat()} ) self.airflow_client.wait_for_dag_run( dag_id="example_xcom_test", diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/base_remote_log_search_test.py b/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/base_remote_log_search_test.py index 797c8324c18..1f680f9d14f 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/base_remote_log_search_test.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/base_remote_log_search_test.py @@ -17,7 +17,7 @@ from __future__ import annotations import time -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest @@ -62,7 +62,7 @@ class BaseRemoteLoggingSearchTest: resp = self.airflow_client.trigger_dag( self.dag_id, - json={"logical_date": datetime.now(timezone.utc).isoformat()}, + json={"logical_date": datetime.now(UTC).isoformat()}, ) run_id = resp["dag_run_id"] state = self.airflow_client.wait_for_dag_run( @@ -117,7 +117,7 @@ class BaseRemoteLoggingSearchTest: self.airflow_client.un_pause_dag(dag_id) resp = self.airflow_client.trigger_dag( dag_id, - json={"logical_date": datetime.now(timezone.utc).isoformat()}, + json={"logical_date": datetime.now(UTC).isoformat()}, ) run_id = resp["dag_run_id"] state = self.airflow_client.wait_for_dag_run(dag_id=dag_id, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/clients.py b/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/clients.py index f555cd11542..87b9b816637 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/clients.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/e2e_test_utils/clients.py @@ -17,7 +17,7 @@ from __future__ import annotations import time -from datetime import datetime, timezone +from datetime import UTC, datetime from functools import cached_property import boto3 @@ -174,7 +174,7 @@ class AirflowClient: """Trigger a DAG and wait for it to complete.""" self.un_pause_dag(dag_id) - resp = self.trigger_dag(dag_id, json=json or {"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = self.trigger_dag(dag_id, json=json or {"logical_date": datetime.now(UTC).isoformat()}) # Wait for the DAG run to complete return self.wait_for_dag_run( diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_concurrent_xcom.py b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_concurrent_xcom.py index 90e9116ca8d..a040e8c494e 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_concurrent_xcom.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_concurrent_xcom.py @@ -24,7 +24,7 @@ Asserts the task succeeds and the concurrent pull beats the sequential one. from __future__ import annotations from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest @@ -57,7 +57,7 @@ class _CompletedRun: def completed_run() -> _CompletedRun: """Trigger ``concurrent_xcom_dag`` once and wait for it to finish.""" client = AirflowClient() - resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=_DAG_ID, run_id=run_id, timeout=_GO_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=_DAG_ID, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_dag.py b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_dag.py index 02c1ccff6bd..13a8af2f54d 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_dag.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_dag.py @@ -68,7 +68,7 @@ from __future__ import annotations import re import time from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest @@ -126,7 +126,7 @@ def completed_run() -> _CompletedRun: in this module inspects the resulting states, XComs, and logs. """ client = AirflowClient() - resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=_DAG_ID, run_id=run_id, timeout=_GO_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=_DAG_ID, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_task_state.py b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_task_state.py index 37cf349a3f7..3a8f2a81afb 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_task_state.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_task_state.py @@ -23,7 +23,7 @@ proven to have reached the database. from __future__ import annotations from dataclasses import dataclass -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from http import HTTPStatus import pytest @@ -54,7 +54,7 @@ class _CompletedRun: @pytest.fixture(scope="module") def completed_run() -> _CompletedRun: client = AirflowClient() - resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=_DAG_ID, run_id=run_id, timeout=_GO_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=_DAG_ID, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_taskflow_binding.py b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_taskflow_binding.py index d01924994c3..525d546a6ee 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_taskflow_binding.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_taskflow_binding.py @@ -28,7 +28,7 @@ from __future__ import annotations import time from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest @@ -86,7 +86,7 @@ class _CompletedRun: def completed_run() -> _CompletedRun: """Trigger ``taskflow_binding_dag`` once and wait for it to finish.""" client = AirflowClient() - resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=_DAG_ID, run_id=run_id, timeout=_GO_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=_DAG_ID, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_variable_write.py b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_variable_write.py index b4db9bd8482..d9ca8eb08e9 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_variable_write.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/go_sdk_tests/test_go_sdk_variable_write.py @@ -24,7 +24,7 @@ written, so both paths go through the supervisor and the Task Execution API. from __future__ import annotations from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime from http import HTTPStatus import pytest @@ -52,7 +52,7 @@ class _CompletedRun: def completed_run() -> _CompletedRun: """Trigger ``variable_write_dag`` once and wait for it to finish.""" client = AirflowClient() - resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(_DAG_ID, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=_DAG_ID, run_id=run_id, timeout=_GO_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=_DAG_ID, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/java_sdk_tests/test_java_sdk_dag.py b/airflow-e2e-tests/tests/airflow_e2e_tests/java_sdk_tests/test_java_sdk_dag.py index 60ddf7a8d28..fcd8d8d01fa 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/java_sdk_tests/test_java_sdk_dag.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/java_sdk_tests/test_java_sdk_dag.py @@ -69,7 +69,7 @@ from __future__ import annotations import time from dataclasses import dataclass, field -from datetime import datetime, timezone +from datetime import UTC, datetime from http import HTTPStatus from typing import TYPE_CHECKING @@ -155,7 +155,7 @@ def _trigger_and_wait_for_dag(dag_id: str, timeout: int) -> _CompletedRun: client = AirflowClient() run_id = None try: - resp = client.trigger_dag(dag_id, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(dag_id, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=dag_id, run_id=run_id, timeout=timeout) ti_resp = client.get_task_instances(dag_id=dag_id, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/harness.py b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/harness.py index e1972a6006d..7ab2946fa03 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/harness.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/openlineage_tests/harness.py @@ -75,7 +75,7 @@ class OpenLineageE2ERunner: def __init__(self, client: AirflowClient): self.client = client - now = dt.datetime.now(tz=dt.timezone.utc) + now = dt.datetime.now(tz=dt.UTC) self.run_id = f"ci_triggered_{now.isoformat()}" self.retry_run_id = f"{self.run_id}_retry1" # dag_id -> whether its final state came from retry_run_id rather than run_id; populated by run(). @@ -110,7 +110,7 @@ class OpenLineageE2ERunner: console.print(f"[red]Failed to unpause Dag `{dag_id}`: {exc}") def trigger_dag_run(self, dag_id: str, run_id: str) -> bool: - now = dt.datetime.now(tz=dt.timezone.utc).isoformat() + now = dt.datetime.now(tz=dt.UTC).isoformat() payload = {"dag_run_id": run_id, "logical_date": now, "conf": {}} try: self.client._make_request(method="POST", endpoint=f"dags/{dag_id}/dagRuns", json=payload) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/remote_log_tests/test_remote_logging.py b/airflow-e2e-tests/tests/airflow_e2e_tests/remote_log_tests/test_remote_logging.py index e958132a5de..0795828d13f 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/remote_log_tests/test_remote_logging.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/remote_log_tests/test_remote_logging.py @@ -17,7 +17,7 @@ from __future__ import annotations import time -from datetime import datetime, timezone +from datetime import UTC, datetime import pytest @@ -37,7 +37,7 @@ class TestRemoteLogging: self.airflow_client.un_pause_dag(TestRemoteLogging.dag_id) resp = self.airflow_client.trigger_dag( - TestRemoteLogging.dag_id, json={"logical_date": datetime.now(timezone.utc).isoformat()} + TestRemoteLogging.dag_id, json={"logical_date": datetime.now(UTC).isoformat()} ) state = self.airflow_client.wait_for_dag_run( dag_id=TestRemoteLogging.dag_id, diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/ts_sdk_tests/test_ts_sdk_dag.py b/airflow-e2e-tests/tests/airflow_e2e_tests/ts_sdk_tests/test_ts_sdk_dag.py index fe09cc2eb81..5424e04dad7 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/ts_sdk_tests/test_ts_sdk_dag.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/ts_sdk_tests/test_ts_sdk_dag.py @@ -37,7 +37,7 @@ from __future__ import annotations import time from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime from http import HTTPStatus import pytest @@ -89,7 +89,7 @@ class _CompletedRun: def _trigger_and_wait(dag_id: str) -> _CompletedRun: client = AirflowClient() - resp = client.trigger_dag(dag_id, json={"logical_date": datetime.now(timezone.utc).isoformat()}) + resp = client.trigger_dag(dag_id, json={"logical_date": datetime.now(UTC).isoformat()}) run_id = resp["dag_run_id"] state = client.wait_for_dag_run(dag_id=dag_id, run_id=run_id, timeout=_TS_TASK_TIMEOUT) ti_resp = client.get_task_instances(dag_id=dag_id, run_id=run_id) diff --git a/airflow-e2e-tests/tests/airflow_e2e_tests/xcom_object_storage_tests/test_xcom_object_storage_backend.py b/airflow-e2e-tests/tests/airflow_e2e_tests/xcom_object_storage_tests/test_xcom_object_storage_backend.py index 8ddb9738b6b..e463dd0dd41 100644 --- a/airflow-e2e-tests/tests/airflow_e2e_tests/xcom_object_storage_tests/test_xcom_object_storage_backend.py +++ b/airflow-e2e-tests/tests/airflow_e2e_tests/xcom_object_storage_tests/test_xcom_object_storage_backend.py @@ -17,7 +17,7 @@ from __future__ import annotations import time -from datetime import datetime, timezone +from datetime import UTC, datetime from pprint import pprint from uuid import uuid4 @@ -41,7 +41,7 @@ class TestXComObjectStorageBackend: self.dag_id, json={ "dag_run_id": f"test_xcom_object_storage_backend_{uuid4()}", - "logical_date": datetime.now(timezone.utc).isoformat(), + "logical_date": datetime.now(UTC).isoformat(), }, ) dag_run_id = trigger_resp["dag_run_id"] diff --git a/dev/breeze/src/airflow_breeze/utils/github.py b/dev/breeze/src/airflow_breeze/utils/github.py index 34c252bd431..9f2c9312d51 100644 --- a/dev/breeze/src/airflow_breeze/utils/github.py +++ b/dev/breeze/src/airflow_breeze/utils/github.py @@ -23,7 +23,7 @@ import sys import tempfile import zipfile from collections.abc import Mapping, Sequence -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import TYPE_CHECKING, Any, cast @@ -159,7 +159,7 @@ def log_github_rate_limit_error(response: Response) -> None: remaining_int = int(remaining) if remaining and remaining.isdigit() else None if reset and reset.isdigit(): - reset_dt = datetime.fromtimestamp(int(reset), tz=timezone.utc) + reset_dt = datetime.fromtimestamp(int(reset), tz=UTC) reset_time = reset_dt.strftime("%Y-%m-%d %H:%M:%S UTC") else: reset_time = "unknown" @@ -342,7 +342,7 @@ def get_tag_date(tag: str) -> str | None: timestamp: int = ( tag_object.committed_date if hasattr(tag_object, "committed_date") else tag_object.tagged_date ) - return datetime.fromtimestamp(timestamp, tz=timezone.utc).strftime("%Y-%m-%dT%H:%M:%SZ") + return datetime.fromtimestamp(timestamp, tz=UTC).strftime("%Y-%m-%dT%H:%M:%SZ") def download_artifact_from_run_id(run_id: str, output_file: Path, github_repository: str, github_token: str): diff --git a/dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py b/dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py index 2a0d6918b50..9b9eb299bdb 100644 --- a/dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py +++ b/dev/breeze/src/airflow_breeze/utils/kubernetes_utils.py @@ -26,7 +26,7 @@ import stat import sys import tarfile import tempfile -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from time import sleep from typing import Any, NamedTuple @@ -414,7 +414,7 @@ def get_kubernetes_port_numbers(python: str, kubernetes_version: str) -> tuple[i def _attempt_to_connect(port_number: int, output: Output | None, wait_seconds: int = 0) -> bool: import requests - start_time = datetime.now(timezone.utc) + start_time = datetime.now(UTC) sleep_seconds = 5 for attempt in itertools.count(1): get_console(output=output).print(f"[info]Connecting to localhost:{port_number}. Num try: {attempt}") @@ -437,7 +437,7 @@ def _attempt_to_connect(port_number: int, output: Output | None, wait_seconds: i f"[warning]Error when connecting to localhost:{port_number} " f"{response.status_code}: {response.reason}" ) - current_time = datetime.now(timezone.utc) + current_time = datetime.now(UTC) if current_time - start_time > timedelta(seconds=wait_seconds): if wait_seconds > 0: get_console(output=output).print(f"[error]More than {wait_seconds} passed. Exiting.") diff --git a/dev/breeze/src/airflow_breeze/utils/parallel.py b/dev/breeze/src/airflow_breeze/utils/parallel.py index 61fa55f9589..3ac12921600 100644 --- a/dev/breeze/src/airflow_breeze/utils/parallel.py +++ b/dev/breeze/src/airflow_breeze/utils/parallel.py @@ -283,7 +283,7 @@ class ParallelMonitor(Thread): self.time_in_seconds = time_in_seconds self.debug_resources = debug_resources self.progress_matcher = progress_matcher - self.start_time = datetime.datetime.now(tz=datetime.timezone.utc) + self.start_time = datetime.datetime.now(tz=datetime.UTC) def print_single_progress(self, output: Output): if self.progress_matcher: @@ -312,7 +312,7 @@ class ParallelMonitor(Thread): def print_summary(self): import psutil - time_passed = datetime.datetime.now(tz=datetime.timezone.utc) - self.start_time + time_passed = datetime.datetime.now(tz=datetime.UTC) - self.start_time get_console().rule() for output in self.outputs: self.print_single_progress(output) diff --git a/dev/breeze/tests/test_set_milestone.py b/dev/breeze/tests/test_set_milestone.py index 82b16c7692e..0c79fa5c934 100644 --- a/dev/breeze/tests/test_set_milestone.py +++ b/dev/breeze/tests/test_set_milestone.py @@ -18,7 +18,7 @@ from __future__ import annotations import json import re -from datetime import datetime, timezone +from datetime import UTC, datetime from unittest.mock import MagicMock, patch import pytest @@ -202,21 +202,13 @@ class TestShouldSkipMilestoneTagging: def test_skip_when_backport_unlabeled_with_no_replacement(self): # Events show backport removal, no backport on PR now → skip (check 2). - events = [ - _unlabel_event( - "backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc) - ) - ] + events = [_unlabel_event("backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC))] assert _should_skip_milestone_tagging(["kind:bug"], events=events) def test_no_skip_when_backport_replaced(self): # Events show backport-to-v3-1 removal but v3-2 remains on the PR → no skip. # The caller's regular evaluation will pick up the new label. - events = [ - _unlabel_event( - "backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc) - ) - ] + events = [_unlabel_event("backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC))] assert not _should_skip_milestone_tagging(["backport-to-v3-2-test", "kind:bug"], events=events) def test_no_skip_when_no_removal_event(self): @@ -224,20 +216,14 @@ class TestShouldSkipMilestoneTagging: assert not _should_skip_milestone_tagging(["backport-to-v3-1-test", "kind:bug"], events=[]) def test_no_skip_when_unrelated_label_removed(self): - events = [ - _unlabel_event("kind:documentation", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc)) - ] + events = [_unlabel_event("kind:documentation", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC))] assert not _should_skip_milestone_tagging(["kind:bug"], events=events) def test_events_check_takes_precedence_over_static_labels(self): # Both check 2 (events) and check 3 (static label) would fire here; # the function returns True on the first one — events — and never logs # the static-label reason. - events = [ - _unlabel_event( - "backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc) - ) - ] + events = [_unlabel_event("backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC))] assert _should_skip_milestone_tagging(["area:CI"], events=events) def test_events_none_disables_events_check(self): @@ -251,10 +237,8 @@ class TestGetRemovedBackportLabelsFromEvents: def test_returns_all_unlabel_events_for_backports(self): events = [ - _unlabel_event( - "backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc) - ), - _unlabel_event("backport-to-v3-2-test", "bob", datetime(2026, 5, 23, 14, 0, tzinfo=timezone.utc)), + _unlabel_event("backport-to-v3-1-test", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC)), + _unlabel_event("backport-to-v3-2-test", "bob", datetime(2026, 5, 23, 14, 0, tzinfo=UTC)), ] assert _get_removed_backport_labels_from_events(events) == { "backport-to-v3-1-test", @@ -262,9 +246,7 @@ class TestGetRemovedBackportLabelsFromEvents: } def test_ignores_unrelated_label_unlabel_events(self): - events = [ - _unlabel_event("kind:documentation", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=timezone.utc)) - ] + events = [_unlabel_event("kind:documentation", "alice", datetime(2026, 5, 23, 12, 0, tzinfo=UTC))] assert _get_removed_backport_labels_from_events(events) == set() def test_ignores_non_unlabeled_events(self): @@ -733,7 +715,7 @@ However, **no open milestone was found** matching: {expected_search_criteria} _unlabel_event( "backport-to-v3-2-test", "shahar1", - datetime(2026, 5, 23, 20, 32, 17, tzinfo=timezone.utc), + datetime(2026, 5, 23, 20, 32, 17, tzinfo=UTC), ), ] mock_get_client.return_value = mock_gh @@ -785,7 +767,7 @@ However, **no open milestone was found** matching: {expected_search_criteria} _unlabel_event( "backport-to-v3-2-test", "testuser", - datetime(2026, 5, 23, 20, 32, 17, tzinfo=timezone.utc), + datetime(2026, 5, 23, 20, 32, 17, tzinfo=UTC), ), ] mock_get_client.return_value = mock_gh @@ -834,7 +816,7 @@ However, **no open milestone was found** matching: {expected_search_criteria} _unlabel_event( "backport-to-v3-1-test", "testuser", - datetime(2026, 5, 23, 20, 30, 0, tzinfo=timezone.utc), + datetime(2026, 5, 23, 20, 30, 0, tzinfo=UTC), ), ] mock_milestone = MagicMock() diff --git a/dev/registry/extract_connections.py b/dev/registry/extract_connections.py index ebb269193c3..c61eee3c3ea 100644 --- a/dev/registry/extract_connections.py +++ b/dev/registry/extract_connections.py @@ -39,7 +39,7 @@ import argparse import json import sys from collections import defaultdict -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import Any @@ -204,7 +204,7 @@ def main(): hooks, form_widgets, field_behaviours = HookMetaService._get_hooks_with_mocked_fab() - generated_at = datetime.now(timezone.utc).isoformat() + generated_at = datetime.now(UTC).isoformat() # Group connection types by provider provider_connections: dict[str, list[dict]] = defaultdict(list) diff --git a/dev/registry/extract_parameters.py b/dev/registry/extract_parameters.py index 7f776ae1645..6e09084bc04 100644 --- a/dev/registry/extract_parameters.py +++ b/dev/registry/extract_parameters.py @@ -50,7 +50,7 @@ import textwrap import typing from collections import defaultdict from dataclasses import dataclass -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path import yaml @@ -1233,7 +1233,7 @@ def main(): for p in providers_data.get("providers", []): provider_versions[p["id"]] = p["version"] - generated_at = datetime.now(timezone.utc).isoformat() + generated_at = datetime.now(UTC).isoformat() _main_discover( provider_versions, generated_at, diff --git a/kubernetes-tests/tests/kubernetes_tests/test_base.py b/kubernetes-tests/tests/kubernetes_tests/test_base.py index caa82946718..9a7a32dd078 100644 --- a/kubernetes-tests/tests/kubernetes_tests/test_base.py +++ b/kubernetes-tests/tests/kubernetes_tests/test_base.py @@ -22,7 +22,7 @@ import re import subprocess import tempfile import time -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from subprocess import check_call, check_output from typing import Literal @@ -100,7 +100,7 @@ class BaseK8STest: with open(output_file_path, "w") as output_file: print("=" * 80, file=output_file) print(f"Describe resources for namespace {namespace}", file=output_file) - print(f"Datetime: {datetime.now(tz=timezone.utc)}", file=output_file) + print(f"Datetime: {datetime.now(tz=UTC)}", file=output_file) print("=" * 80, file=output_file) print("Describing pods", file=output_file) print("-" * 80, file=output_file) @@ -349,7 +349,7 @@ class BaseK8STest: post_string = f"http://{host}/dags/{dag_id}/dagRuns" print(f"Calling [start_dag]#2 {post_string}") - logical_date = datetime.now(timezone.utc).isoformat() + logical_date = datetime.now(UTC).isoformat() # Trigger a new dagrun result = self.session.post(post_string, json={"logical_date": logical_date}) try: diff --git a/scripts/ci/analyze_ci_job_durations.py b/scripts/ci/analyze_ci_job_durations.py index 5aa27f09731..43cfd092b19 100644 --- a/scripts/ci/analyze_ci_job_durations.py +++ b/scripts/ci/analyze_ci_job_durations.py @@ -75,7 +75,7 @@ import json import os import subprocess import sys -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import TypedDict @@ -725,7 +725,7 @@ def main() -> None: runs = get_recent_runs(repo, workflow, branch, max_runs, only_successful, event) # A degraded Actions API can return an old page of runs, and without this check its # weeks-old durations were reported as "latest" and raised a false alert. - newest_age_days = compute_run_age_days(runs[0], datetime.now(timezone.utc)) if runs else None + newest_age_days = compute_run_age_days(runs[0], datetime.now(UTC)) if runs else None if newest_age_days is not None and newest_age_days > max_latest_run_age_days: print( f"::warning::The newest usable run (#{runs[0]['run_number']}) is " diff --git a/scripts/ci/notify_uv_lock_conflicts.py b/scripts/ci/notify_uv_lock_conflicts.py index e4d28c64e19..4c0a3aff1e5 100644 --- a/scripts/ci/notify_uv_lock_conflicts.py +++ b/scripts/ci/notify_uv_lock_conflicts.py @@ -49,7 +49,7 @@ import re import sys import time from dataclasses import dataclass -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from typing import Any import httpx @@ -428,7 +428,7 @@ def main() -> int: short_sha = sha[:7] commit_url = f"https://github.com/{owner}/{repo}/commit/{sha}" - stale_cut = datetime.now(tz=timezone.utc) - timedelta(days=STALE_DAYS) + stale_cut = datetime.now(tz=UTC) - timedelta(days=STALE_DAYS) with GitHubGraphQL(token) as client: source_pr = resolve_source_pr(client, owner, repo, sha, short_sha) diff --git a/scripts/ci/prek/upgrade_important_versions.py b/scripts/ci/prek/upgrade_important_versions.py index 075687e2595..f385c81be2e 100755 --- a/scripts/ci/prek/upgrade_important_versions.py +++ b/scripts/ci/prek/upgrade_important_versions.py @@ -37,7 +37,7 @@ import os import re import subprocess import sys -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from enum import Enum from pathlib import Path @@ -277,7 +277,7 @@ def _is_version_within_cooldown(releases: dict, version: str, cooldown_hours: fl return False upload_time = datetime.fromisoformat(files[0]["upload_time_iso_8601"].replace("Z", "+00:00")) effective_hours = COOLDOWN_DAYS * 24 if cooldown_hours is None else cooldown_hours - cutoff = datetime.now(timezone.utc) - timedelta(hours=effective_hours) + cutoff = datetime.now(UTC) - timedelta(hours=effective_hours) return upload_time > cutoff diff --git a/scripts/ci/slack_notification_state.py b/scripts/ci/slack_notification_state.py index bdeca122bea..fe675dafa15 100644 --- a/scripts/ci/slack_notification_state.py +++ b/scripts/ci/slack_notification_state.py @@ -44,7 +44,7 @@ import json import os import subprocess import sys -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path REMINDER_INTERVAL_HOURS = 24 @@ -140,7 +140,7 @@ def determine_action(current_failures: list[str], prev_state: dict | None) -> st """ prev_failures = sorted(prev_state.get("failures", [])) if prev_state else [] prev_notified = prev_state.get("last_notified") if prev_state else None - now = datetime.now(timezone.utc) + now = datetime.now(UTC) if current_failures: if not prev_failures: @@ -164,7 +164,7 @@ def determine_action(current_failures: list[str], prev_state: dict | None) -> st def save_state(current_failures: list[str], action: str, prev_notified: str | None) -> None: """Save current state to file for upload as artifact.""" - now = datetime.now(timezone.utc) + now = datetime.now(UTC) STATE_DIR.mkdir(parents=True, exist_ok=True) new_state = { diff --git a/scripts/in_container/update_quarantined_test_status.py b/scripts/in_container/update_quarantined_test_status.py index d983dbfc0d7..bd57d87576a 100755 --- a/scripts/in_container/update_quarantined_test_status.py +++ b/scripts/in_container/update_quarantined_test_status.py @@ -20,7 +20,7 @@ from __future__ import annotations import os import re import sys -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path from typing import NamedTuple from urllib.parse import urlsplit @@ -244,7 +244,7 @@ if __name__ == "__main__": print() with Path(__file__).resolve().with_name("quarantine_issue_header.md").open() as f: header = jinja2.Template(f.read(), autoescape=True, undefined=StrictUndefined).render( - DATE_UTC_NOW=datetime.now(tz=timezone.utc).isoformat("T", timespec="seconds") + DATE_UTC_NOW=datetime.now(tz=UTC).isoformat("T", timespec="seconds") ) quarantined_issue.edit( title=None, body=f"{header}\n\n{table}", state="open" if test_results else "closed" diff --git a/scripts/tests/ci/prek/test_upgrade_dependency_floors.py b/scripts/tests/ci/prek/test_upgrade_dependency_floors.py index 5454f723537..9e75e8d247c 100644 --- a/scripts/tests/ci/prek/test_upgrade_dependency_floors.py +++ b/scripts/tests/ci/prek/test_upgrade_dependency_floors.py @@ -18,7 +18,7 @@ from __future__ import annotations import subprocess import textwrap -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from unittest import mock @@ -202,7 +202,7 @@ def test_no_exclusion_for_plain_floor(tmp_path): assert get_exclusion_reason("boto3", [_site("boto3>=1.40; python_version < '3.14'")], config) is None -NOW = datetime(2026, 9, 24, tzinfo=timezone.utc) +NOW = datetime(2026, 9, 24, tzinfo=UTC) AGE = timedelta(days=180) diff --git a/scripts/tests/ci/prek/test_upgrade_important_versions.py b/scripts/tests/ci/prek/test_upgrade_important_versions.py index e82ae344cfa..6eb9d28d663 100644 --- a/scripts/tests/ci/prek/test_upgrade_important_versions.py +++ b/scripts/tests/ci/prek/test_upgrade_important_versions.py @@ -19,6 +19,7 @@ from __future__ import annotations +from datetime import UTC from unittest import mock import pytest @@ -199,12 +200,12 @@ def test_remove_override_entry_no_match_is_noop(): def test_is_version_within_cooldown_uses_per_package_override(): """A shorter per-package cooldown lets a release through that the global window would block.""" - from datetime import datetime, timedelta, timezone + from datetime import datetime, timedelta from ci.prek.upgrade_important_versions import _is_version_within_cooldown # Published 2 days ago — inside the 4-day global window, outside a 6-hour window. - two_days_ago = (datetime.now(timezone.utc) - timedelta(days=2)).isoformat() + two_days_ago = (datetime.now(UTC) - timedelta(days=2)).isoformat() releases = {"1.0.1": [{"upload_time_iso_8601": two_days_ago.replace("+00:00", "Z")}]} # No override → global 4-day cooldown applies → version is "within cooldown". diff --git a/scripts/tests/ci/test_notify_uv_lock_conflicts.py b/scripts/tests/ci/test_notify_uv_lock_conflicts.py index f187d0c3224..333aead5edf 100644 --- a/scripts/tests/ci/test_notify_uv_lock_conflicts.py +++ b/scripts/tests/ci/test_notify_uv_lock_conflicts.py @@ -19,7 +19,7 @@ from __future__ import annotations import importlib.util import sys import types -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta from pathlib import Path from typing import Any from unittest.mock import MagicMock @@ -56,7 +56,7 @@ def mod(): # A recent timestamp — well inside the stale window — used by fixture PRs. FRESH_ISO = "2099-01-01T12:00:00Z" -STALE_CUT = datetime(1970, 1, 1, tzinfo=timezone.utc) +STALE_CUT = datetime(1970, 1, 1, tzinfo=UTC) SHORT_SHA = "abc1234" @@ -113,11 +113,11 @@ class TestPrNumberRegex: class TestParseUpdatedAt: def test_handles_zulu_suffix(self, mod): dt = mod.parse_updated_at("2025-04-24T10:20:30Z") - assert dt == datetime(2025, 4, 24, 10, 20, 30, tzinfo=timezone.utc) + assert dt == datetime(2025, 4, 24, 10, 20, 30, tzinfo=UTC) def test_handles_explicit_offset(self, mod): dt = mod.parse_updated_at("2025-04-24T10:20:30+00:00") - assert dt == datetime(2025, 4, 24, 10, 20, 30, tzinfo=timezone.utc) + assert dt == datetime(2025, 4, 24, 10, 20, 30, tzinfo=UTC) class TestClassify: @@ -126,7 +126,7 @@ class TestClassify: assert kind == "drafts" and entry is None def test_stale(self, mod): - cutoff = datetime.now(tz=timezone.utc) - timedelta(days=14) + cutoff = datetime.now(tz=UTC) - timedelta(days=14) old_pr = make_pr(updated_at="2000-01-01T00:00:00Z") kind, entry = mod.classify(old_pr, cutoff, SHORT_SHA) assert kind == "stale" and entry is None @@ -237,9 +237,9 @@ class TestScanOpenPrs: def test_early_exit_on_stale(self, mod): """A stale PR stops pagination even if hasNextPage is True.""" client = MagicMock() - recent_cut = datetime.now(tz=timezone.utc) - timedelta(days=1) - fresh = (datetime.now(tz=timezone.utc)).isoformat().replace("+00:00", "Z") - stale = (datetime.now(tz=timezone.utc) - timedelta(days=30)).isoformat().replace("+00:00", "Z") + recent_cut = datetime.now(tz=UTC) - timedelta(days=1) + fresh = (datetime.now(tz=UTC)).isoformat().replace("+00:00", "Z") + stale = (datetime.now(tz=UTC) - timedelta(days=30)).isoformat().replace("+00:00", "Z") client.call.return_value = self._page( [ make_pr(number=1, updated_at=fresh, mergeable="CONFLICTING"), diff --git a/scripts/tests/ci/testing/test_compute_remaining_test_timeout.py b/scripts/tests/ci/testing/test_compute_remaining_test_timeout.py index ff9ef7a4ffa..c42bdedd12e 100644 --- a/scripts/tests/ci/testing/test_compute_remaining_test_timeout.py +++ b/scripts/tests/ci/testing/test_compute_remaining_test_timeout.py @@ -18,7 +18,7 @@ from __future__ import annotations import importlib.util import sys -from datetime import datetime, timezone +from datetime import UTC, datetime from pathlib import Path import pytest @@ -61,7 +61,7 @@ def test_compute_remaining_test_timeout( @time_machine.travel("2026-08-29 12:10:00+00:00", tick=False) def test_main_derives_the_budget_left_from_the_job_start_time(timeout_module, monkeypatch, capsys): - job_start_epoch = int(datetime(2026, 8, 29, 12, 0, tzinfo=timezone.utc).timestamp()) + job_start_epoch = int(datetime(2026, 8, 29, 12, 0, tzinfo=UTC).timestamp()) monkeypatch.setattr( sys, "argv", diff --git a/task-sdk-integration-tests/tests/task_sdk_tests/jwt_plugin.py b/task-sdk-integration-tests/tests/task_sdk_tests/jwt_plugin.py index 3caf4193eea..3bc88cbea8e 100644 --- a/task-sdk-integration-tests/tests/task_sdk_tests/jwt_plugin.py +++ b/task-sdk-integration-tests/tests/task_sdk_tests/jwt_plugin.py @@ -21,7 +21,7 @@ from __future__ import annotations import os import uuid -from datetime import datetime, timezone +from datetime import UTC, datetime from typing import Any import jwt @@ -57,7 +57,7 @@ class JWTTokenGenerator: Returns: JWT token as a string """ - now = int(datetime.now(timezone.utc).timestamp()) + now = int(datetime.now(UTC).timestamp()) claims = { "jti": uuid.uuid4().hex, diff --git a/task-sdk-integration-tests/tests/task_sdk_tests/test_dag_run_operations.py b/task-sdk-integration-tests/tests/task_sdk_tests/test_dag_run_operations.py index 29792dcab21..c1463b306b9 100644 --- a/task-sdk-integration-tests/tests/task_sdk_tests/test_dag_run_operations.py +++ b/task-sdk-integration-tests/tests/task_sdk_tests/test_dag_run_operations.py @@ -26,7 +26,7 @@ These tests validate the Execution API endpoints for DAG Run operations: from __future__ import annotations -from datetime import datetime, timedelta, timezone +from datetime import UTC, datetime, timedelta import pytest @@ -145,7 +145,7 @@ def test_dag_run_get_previous(sdk_client, dag_info): response = sdk_client.dag_runs.get_previous( dag_id=dag_info["dag_id"], - logical_date=datetime.now(timezone.utc) + timedelta(seconds=10), + logical_date=datetime.now(UTC) + timedelta(seconds=10), ) console.print(" Previous DAG Run Response ".center(72, "=")) @@ -169,7 +169,7 @@ def test_dag_run_get_previous_not_found(sdk_client): response = sdk_client.dag_runs.get_previous( dag_id="not_exist", - logical_date=datetime.now(timezone.utc) + timedelta(seconds=10), + logical_date=datetime.now(UTC) + timedelta(seconds=10), ) console.print(" Non-existent Previous DAG Run Response ".center(72, "="))