diff --git a/src/openai/_models.py b/src/openai/_models.py index ed4c1f82d6..664405ab41 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] + args = get_args(type_) + if len(args) < 2: + return value + items_type = args[1] return {key: construct_type(value=item, type_=items_type) for key, item in value.items()} if ( diff --git a/src/openai/types/beta/realtime/realtime_response_status.py b/src/openai/types/beta/realtime/realtime_response_status.py index 7189cd58a1..986da1c8e4 100644 --- a/src/openai/types/beta/realtime/realtime_response_status.py +++ b/src/openai/types/beta/realtime/realtime_response_status.py @@ -12,6 +12,9 @@ class Error(BaseModel): code: Optional[str] = None """Error code, if any.""" + message: Optional[str] = None + """A human-readable description of the error, if any.""" + type: Optional[str] = None """The type of error.""" diff --git a/src/openai/types/realtime/realtime_response_status.py b/src/openai/types/realtime/realtime_response_status.py index 26b272ae5a..967e48886f 100644 --- a/src/openai/types/realtime/realtime_response_status.py +++ b/src/openai/types/realtime/realtime_response_status.py @@ -17,6 +17,9 @@ class Error(BaseModel): code: Optional[str] = None """Error code, if any.""" + message: Optional[str] = None + """A human-readable description of the error, if any.""" + type: Optional[str] = None """The type of error.""" diff --git a/tests/lib/test_realtime_response_status.py b/tests/lib/test_realtime_response_status.py new file mode 100644 index 0000000000..a4c2302f73 --- /dev/null +++ b/tests/lib/test_realtime_response_status.py @@ -0,0 +1,31 @@ +from __future__ import annotations + +from pydantic import BaseModel +import pytest + +from openai.types.beta.realtime import RealtimeResponseStatus as BetaRealtimeResponseStatus +from openai.types.realtime import RealtimeResponseStatus as RealtimeResponseStatus + + +@pytest.mark.parametrize( + "status_cls", + [BetaRealtimeResponseStatus, RealtimeResponseStatus], + ids=["beta", "realtime"], +) +def test_realtime_response_status_error_message(status_cls: type[BaseModel]) -> None: + status = status_cls.model_validate( + { + "error": { + "code": "bad_request", + "message": "The model could not process the request.", + "type": "invalid_request_error", + }, + "type": "failed", + } + ) + + assert status.error is not None + assert status.error.code == "bad_request" + assert status.error.message == "The model could not process the request." + assert status.error.type == "invalid_request_error" + assert status.type == "failed" diff --git a/tests/test_models.py b/tests/test_models.py index cc204bac1d..9f8be87f3b 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -964,6 +964,10 @@ def __getattr__(self, attr: str) -> Item: ... assert model.other == "foo" +def test_bare_dict_annotation() -> None: + assert construct_type(value={"key": "value"}, type_=dict) == {"key": "value"} + + # NOTE: Workaround for Pydantic Iterable behavior. # Iterable fields are replaced with a ValidatorIterator and may be consumed # during serialization, which can cause subsequent dumps to return empty data.