From 5cb7ba509e79ed11de6deb28d760f9f122ae221d Mon Sep 17 00:00:00 2001 From: Yufeng He <40085740+he-yufeng@users.noreply.github.com> Date: Sun, 7 Jun 2026 23:59:52 +0800 Subject: [PATCH] fix: handle bare dict type annotations --- src/openai/_models.py | 5 ++++- src/openai/_utils/_transform.py | 12 ++++++++++-- tests/test_models.py | 4 ++++ tests/test_transform.py | 12 ++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/src/openai/_models.py b/src/openai/_models.py index ed4c1f82d6..a63e687025 100644 --- a/src/openai/_models.py +++ b/src/openai/_models.py @@ -657,7 +657,10 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if not is_mapping(value): return value - _, items_type = get_args(type_) # Dict[_, items_type] + if len(args) < 2: + return value + + _, items_type = args # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} if ( diff --git a/src/openai/_utils/_transform.py b/src/openai/_utils/_transform.py index 414f38c340..cd3084a3bb 100644 --- a/src/openai/_utils/_transform.py +++ b/src/openai/_utils/_transform.py @@ -180,7 +180,11 @@ def _transform_recursive( return _transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] + args = get_args(stripped_type) + if len(args) < 2: + return data + + items_type = args[1] return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( @@ -346,7 +350,11 @@ async def _async_transform_recursive( return await _async_transform_typeddict(data, stripped_type) if origin == dict and is_mapping(data): - items_type = get_args(stripped_type)[1] + args = get_args(stripped_type) + if len(args) < 2: + return data + + items_type = args[1] return {key: _transform_recursive(value, annotation=items_type) for key, value in data.items()} if ( diff --git a/tests/test_models.py b/tests/test_models.py index cc204bac1d..3577d7c90e 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -655,6 +655,10 @@ class Model(BaseModel): assert m.value == "foo" +def test_construct_bare_dict_type() -> None: + assert construct_type(value={"key": "value"}, type_=dict) == {"key": "value"} + + def test_discriminated_unions_invalid_data() -> None: class A(BaseModel): type: Literal["a"] diff --git a/tests/test_transform.py b/tests/test_transform.py index bece75dfc7..80ffe90e99 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -397,6 +397,18 @@ class DictItems(TypedDict): assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} +class BareDictParam(TypedDict): + metadata: dict + + +@parametrize +@pytest.mark.asyncio +async def test_bare_dictionary_annotation(use_async: bool) -> None: + data = {"metadata": {"foo_bar": "bar"}} + + assert await transform(data, BareDictParam, use_async) == data + + class TypedDictIterableUnionStr(TypedDict): foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")]