This is an automated email from the ASF dual-hosted git repository. Lee-W pushed a commit to branch ci-upgrade-main in repository https://gitbox.apache.org/repos/asf/airflow.git
commit 07a9df0bacb26f3e44f88214fae2cd8ca22c5bca Author: Wei Lee <[email protected]> AuthorDate: Mon Nov 9 16:48:14 2026 +0800 Fix Redis integration, common.ai fingerprint and OpenAI tests after dependency upgrade The CI dependency upgrade pulls in redis-py 8 and kombu 5.7, which speak RESP3 by default and send HELLO on connect; the Redis 5.0.1 integration image rejects it. It also pulls in pydantic-ai 2.66, which re-raises the unhashable-type TypeError from tool-return serialization as a PydanticSerializationError, so durable fingerprinting returned None instead of falling back, and openai 3.46, which adds an optional field to the usage details that the tests pinned. --- .../providers/common/ai/durable/fingerprint.py | 8 +++++++- .../tests/unit/openai/operators/test_openai.py | 20 ++++---------------- scripts/ci/docker-compose/integration-redis.yml | 2 +- 3 files changed, 12 insertions(+), 18 deletions(-) diff --git a/providers/common/ai/src/airflow/providers/common/ai/durable/fingerprint.py b/providers/common/ai/src/airflow/providers/common/ai/durable/fingerprint.py index bf001af966e..9904be74abf 100644 --- a/providers/common/ai/src/airflow/providers/common/ai/durable/fingerprint.py +++ b/providers/common/ai/src/airflow/providers/common/ai/durable/fingerprint.py @@ -105,7 +105,7 @@ from typing import TYPE_CHECKING, Any, Literal from pydantic import TypeAdapter from pydantic_ai.messages import ModelMessagesTypeAdapter from pydantic_ai.models import ModelRequestParameters -from pydantic_core import to_jsonable_python +from pydantic_core import PydanticSerializationError, to_jsonable_python from airflow.providers.common.ai.utils.masking import mask_secrets from airflow.providers.common.ai.utils.prompt_cache import PROMPT_CACHE_SETTING_NAMES @@ -473,6 +473,12 @@ def _guide(adapter: TypeAdapter[Any], payload: Any) -> tuple[Any, bool]: guide = adapter.dump_python(payload) except TypeError: return None, False + except PydanticSerializationError as exc: + # pydantic-ai 2.66 serializes a tool return through a wrapping field serializer, and pydantic + # re-raises the ``TypeError`` from inside it as this error, keeping only its message. + if "unhashable type" not in str(exc): + raise + return None, False return guide, _check_guide(guide) diff --git a/providers/openai/tests/unit/openai/operators/test_openai.py b/providers/openai/tests/unit/openai/operators/test_openai.py index 39381a117f5..f65d4bcc9bd 100644 --- a/providers/openai/tests/unit/openai/operators/test_openai.py +++ b/providers/openai/tests/unit/openai/operators/test_openai.py @@ -157,17 +157,12 @@ def test_openai_response_operator_execute_xcom_push(do_xcom_push, expected_push_ # slipping through assert_any_call, which only checks presence, not exhaustiveness. assert context["ti"].xcom_push.call_count == expected_push_count if do_xcom_push: + # Expected value is derived from the SDK model so the test does not pin optional fields that + # newer openai releases add to the usage details (e.g. ``cache_write_tokens_details``). context["ti"].xcom_push.assert_any_call(key="response_id", value="resp_123") context["ti"].xcom_push.assert_any_call( key="usage", - value={ - "input_tokens": 5, - "input_tokens_details": {"cache_write_tokens": 0, "cached_tokens": 1}, - "output_tokens": 7, - "output_tokens_details": {"reasoning_tokens": 2}, - "total_tokens": 12, - "try_number": 1, - }, + value={**usage.model_dump(mode="json"), "try_number": 1}, ) @@ -200,14 +195,7 @@ def test_openai_response_operator_execute_records_try_number(): context["ti"].xcom_push.assert_any_call( key="usage", - value={ - "input_tokens": 5, - "input_tokens_details": {"cache_write_tokens": 0, "cached_tokens": 1}, - "output_tokens": 7, - "output_tokens_details": {"reasoning_tokens": 2}, - "total_tokens": 12, - "try_number": 3, - }, + value={**usage.model_dump(mode="json"), "try_number": 3}, ) diff --git a/scripts/ci/docker-compose/integration-redis.yml b/scripts/ci/docker-compose/integration-redis.yml index a1bca55eff9..959d9445842 100644 --- a/scripts/ci/docker-compose/integration-redis.yml +++ b/scripts/ci/docker-compose/integration-redis.yml @@ -17,7 +17,7 @@ --- services: redis: - image: redis:5.0.1 + image: redis:7-alpine labels: org.apache.airflow.breeze: "true" org.apache.airflow.breeze.worktree: "${BREEZE_WORKTREE_PATH:-}"
