diff --git a/src/anthropic/_models.py b/src/anthropic/_models.py index dc00516bc..1d9ad6910 100644 --- a/src/anthropic/_models.py +++ b/src/anthropic/_models.py @@ -647,6 +647,9 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if not is_mapping(value): return value + if not args: + return value + _, items_type = get_args(type_) # Dict[_, items_type] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} @@ -668,6 +671,9 @@ def construct_type(*, value: object, type_: object, metadata: Optional[List[Any] if not is_list(value): return value + if not args: + return value + inner_type = args[0] # List[inner_type] return [construct_type(value=entry, type_=inner_type) for entry in value] diff --git a/src/anthropic/_utils/_transform.py b/src/anthropic/_utils/_transform.py index 1e7e5ac80..72856b9a5 100644 --- a/src/anthropic/_utils/_transform.py +++ b/src/anthropic/_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 not args: + return cast(object, 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 not args: + return cast(object, 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 195f23079..99cd2d7aa 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -655,6 +655,14 @@ class Model(BaseModel): assert m.value == "foo" +def test_construct_type_bare_container_types() -> None: + list_value = ["a", {"nested": "value"}] + dict_value = {"foo": ["bar"]} + + assert construct_type(value=list_value, type_=list) is list_value + assert construct_type(value=dict_value, type_=dict) is dict_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 4a874ff86..9296118ee 100644 --- a/tests/test_transform.py +++ b/tests/test_transform.py @@ -397,6 +397,14 @@ class DictItems(TypedDict): assert await transform({"foo": {"foo_baz": "bar"}}, Dict[str, DictItems], use_async) == {"foo": {"fooBaz": "bar"}} +@parametrize +@pytest.mark.asyncio +async def test_bare_dict_type(use_async: bool) -> None: + data = {"foo_bar": {"baz_qux": "value"}} + + assert await transform(data, dict, use_async) is data + + class TypedDictIterableUnionStr(TypedDict): foo: Annotated[Union[str, Iterable[Baz8]], PropertyInfo(alias="FOO")]