From 26a2c11cfbc84d43c01c7146478733b834e3d1cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20HUBSCHER?= Date: Mon, 27 Oct 2025 18:32:42 +0100 Subject: [PATCH 1/3] Update _models.py to handle Python 3.14 --- src/openai/_models.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index af71a91850..7f3c5c3bd1 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -2,7 +2,7 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast +from typing import TYPE_CHECKING, Any, Annotated, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast from datetime import date, datetime from typing_extensions import ( List, @@ -694,7 +694,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, union).__discriminator__ = details + cast(CachedDiscriminatorType, Annotated[union, details]) return details From 0138621f6d6a3eea316af17abae0d67ce10cc312 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Hubscher?= Date: Wed, 5 Nov 2025 16:00:08 +0100 Subject: [PATCH 2/3] Update caching logic --- src/openai/_models.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index 7f3c5c3bd1..51c3be04fa 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -2,7 +2,8 @@ import os import inspect -from typing import TYPE_CHECKING, Any, Annotated, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast +from typing import TYPE_CHECKING, Any, Type, Tuple, Union, Generic, TypeVar, Callable, Optional, cast +from weakref import WeakKeyDictionary from datetime import date, datetime from typing_extensions import ( List, @@ -77,6 +78,8 @@ ReprArgs = Sequence[Tuple[Optional[str], Any]] +_DISCRIMINATOR_CACHE: "WeakKeyDictionary[type, DiscriminatorDetails]" = WeakKeyDictionary() + @runtime_checkable class _ConfigProtocol(Protocol): @@ -593,11 +596,6 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] return value -@runtime_checkable -class CachedDiscriminatorType(Protocol): - __discriminator__: DiscriminatorDetails - - class DiscriminatorDetails: field_name: str """The name of the discriminator field in the variant class, e.g. @@ -640,8 +638,9 @@ def __init__( def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, ...]) -> DiscriminatorDetails | None: - if isinstance(union, CachedDiscriminatorType): - return union.__discriminator__ + cached_discriminator = _DISCRIMINATOR_CACHE.get(union) + if cached_discriminator is not None: + return cached_discriminator discriminator_field_name: str | None = None @@ -694,7 +693,7 @@ def _build_discriminated_union_meta(*, union: type, meta_annotations: tuple[Any, discriminator_field=discriminator_field_name, discriminator_alias=discriminator_alias, ) - cast(CachedDiscriminatorType, Annotated[union, details]) + _DISCRIMINATOR_CACHE[union] = details return details From 3efca3ddb974a5bdc850b520f182d3b893897e70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Hubscher?= Date: Wed, 5 Nov 2025 16:04:33 +0100 Subject: [PATCH 3/3] Fix tests --- tests/test_models.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/test_models.py b/tests/test_models.py index 410ec3bf4e..48c4748816 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -9,7 +9,7 @@ from openai._utils import PropertyInfo from openai._compat import PYDANTIC_V1, parse_obj, model_dump, model_json -from openai._models import BaseModel, construct_type +from openai._models import BaseModel, construct_type, _DISCRIMINATOR_CACHE class BasicModel(BaseModel): @@ -809,7 +809,7 @@ class B(BaseModel): UnionType = cast(Any, Union[A, B]) - assert not hasattr(UnionType, "__discriminator__") + assert _DISCRIMINATOR_CACHE.get(UnionType) is None m = construct_type( value={"type": "b", "data": "foo"}, type_=cast(Any, Annotated[UnionType, PropertyInfo(discriminator="type")]) @@ -818,7 +818,8 @@ class B(BaseModel): assert m.type == "b" assert m.data == "foo" # type: ignore[comparison-overlap] - discriminator = UnionType.__discriminator__ + discriminator = _DISCRIMINATOR_CACHE.get(UnionType) + assert discriminator is not None m = construct_type( @@ -830,7 +831,7 @@ class B(BaseModel): # if the discriminator details object stays the same between invocations then # we hit the cache - assert UnionType.__discriminator__ is discriminator + assert _DISCRIMINATOR_CACHE.get(UnionType) is discriminator @pytest.mark.skipif(PYDANTIC_V1, reason="TypeAliasType is not supported in Pydantic v1")