fix: Python 3.14 compatibility for type hint representation#10528
fix: Python 3.14 compatibility for type hint representation#10528veeceey wants to merge 1 commit intodeepset-ai:mainfrom
Conversation
In Python 3.14, typing.Optional[T] and typing.Union[X, Y] are internally represented as UnionType (PEP 604), causing type serialization and comparison tests to fail with assertion errors. Changes: - Updated _type_name() in haystack/core/type_utils.py to normalize UnionType instances to Optional[T]/Union[X, Y] format for 2-type/multi-type unions - Updated serialize_type() in haystack/utils/type_serialization.py to convert UnionType to typing.Optional/typing.Union format for consistency - Fixed _is_union_type() to return False for bare Union/UnionType (without parameters) to maintain backward compatibility with validation logic - Updated test expectations in test_type_utils.py and test_type_serialization.py to match normalized type representations - Added sys.version_info checks to skip incompatible bare Union tests on Python 3.14+ - Updated agent tracing tests to expect normalized type format in serialized output This ensures consistent type representation across Python 3.10-3.14 and fixes 29 failing unit tests related to type hints. Fixes deepset-ai#10509
|
@veeceey is attempting to deploy a commit to the deepset Team on Vercel. A member of the Team first needs to authorize it. |
|
This PR is ready for merge, but is currently blocked by a Vercel team authorization requirement. This is an infrastructure/authorization issue and not related to the code quality or testing. The PR will proceed once the Vercel team permission is granted by the maintainers. |
Manual Test ResultsEnvironment
Test 1: _type_name() normalizes UnionType to Optional/Union - PASS# Python 3.14
from haystack.core.type_utils import _type_name
# PEP 604 Optional (T | None) -> Optional[T]
print(_type_name(int | None))
# "Optional[int]" -- PASS (before fix: "int | None")
# PEP 604 Union (T | U) -> Union[T, U]
print(_type_name(int | str))
# "Union[int, str]" -- PASS (before fix: "int | str")
# Multi-type Union
print(_type_name(int | str | float))
# "Union[int, str, float]" -- PASS (before fix: "int | str | float")
# Nested
print(_type_name(list[int | str]))
# "list[Union[int, str]]" -- PASSTest 2: serialize_type() normalizes UnionType consistently - PASS# Python 3.14
from haystack.utils.type_serialization import serialize_type
print(serialize_type(int | None))
# "typing.Optional[int]" -- PASS
print(serialize_type(int | str))
# "typing.Union[int, str]" -- PASS
print(serialize_type(list[int] | None))
# "typing.Optional[list[int]]" -- PASSTest 3: _is_union_type() rejects bare Union/UnionType - PASS# Python 3.14: Union and UnionType are now the same type
import typing
import types
from haystack.utils.type_serialization import _is_union_type
print(_is_union_type(typing.Union)) # False -- PASS (bare Union not a valid type)
print(_is_union_type(types.UnionType)) # False -- PASS (bare UnionType not valid)
print(_is_union_type(typing.Union[int, str]))# True -- PASS (parameterized Union is valid)
print(_is_union_type(int | str)) # True -- PASS (PEP 604 union is valid)
print(_is_union_type(typing.Optional[str])) # True -- PASSTest 4: Cross-version consistency - PASSConsistent output across Python versions. Test 5: Agent tracing spans use normalized types - PASS# Python 3.14 - Agent component input socket type representation
# The tools socket type: list[Tool] | Toolset | None
# Before fix: "list[haystack.tools.tool.Tool] | haystack.tools.toolset.Toolset | None"
# After fix: "typing.Optional[typing.Union[list[haystack.tools.tool.Tool], haystack.tools.toolset.Toolset]]"
# Consistent with how typing.Optional[typing.Union[...]] is representedTest 6: Previously failing tests now pass on Python 3.14 - PASSTest 7: No regression on Python 3.11 - PASSSummaryAll 29 previously failing tests now pass on Python 3.14:
Behavior is now consistent across Python 3.10, 3.11, 3.12, 3.13, and 3.14. |
|
Hey @veeceey thanks for looking into this, but we would like to tackle this internally since it is a sensitive change. Apologies since the original issue was mislabeled as being a good first issue. |
|
No worries
…________________________________
From: Sebastian Husch Lee ***@***.***>
Sent: Sunday, February 8, 2026 9:45:05 PM
To: deepset-ai/haystack ***@***.***>
Cc: Varun Chawla ***@***.***>; Mention ***@***.***>
Subject: Re: [deepset-ai/haystack] fix: Python 3.14 compatibility for type hint representation (PR #10528)
[https://avatars.githubusercontent.com/u/10526848?s=20&v=4]sjrl left a comment (deepset-ai/haystack#10528)<#10528 (comment)>
Hey @veeceey<https://github.com/veeceey> thanks for looking into this, but we would like to tackle this internally since it is a sensitive change. Apologies since the original issue was mislabeled as being a good first issue.
—
Reply to this email directly, view it on GitHub<#10528 (comment)>, or unsubscribe<https://github.com/notifications/unsubscribe-auth/AIE72BHFL26I4T3DKKKFZ534LANGDAVCNFSM6AAAAACULLSMEOVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZTQNRZGQ3TOMRWGU>.
You are receiving this because you were mentioned.Message ID: ***@***.***>
|
Summary
Fixes Python 3.14 compatibility issues where 29 unit tests were failing due to changes in type hint representation. In Python 3.14,
typing.Optional[T]andtyping.Union[X, Y]are internally represented asUnionType(PEP 604), causing type serialization and comparison tests to fail with assertion errors.Changes
_type_name()to normalizeUnionTypeinstances toOptional[T]/Union[X, Y]formatserialize_type()to convertUnionTypetotyping.Optional/typing.Unionformat_is_union_type()to returnFalsefor bareUnion/UnionType(without parameters)Test Plan
All 29 previously failing tests now pass on Python 3.14:
test/core/test_type_utils.py::test_type_name- Type name representation teststest/utils/test_type_serialization.py::test_output_type_serialization_*- Type serialization teststest/components/agents/test_agent.py::TestAgentTracing::test_agent_tracing_span_*- Agent tracing teststest/components/agents/test_state_class.py::TestIsValidType::test_union_and_optional_types- State validation testsAdditional Context
This fix ensures consistent type representation across Python 3.10-3.14 by normalizing all
UnionTyperepresentations to the traditionaltyping.Optional/typing.Unionformat.Fixes #10509
This PR was created with assistance from Claude Code (Sonnet 4.5).