Skip to content

Commit 00d0814

Browse files
committed
fix(structured outputs): resolve memory leak in parse methods
1 parent 534f215 commit 00d0814

File tree

2 files changed

+28
-32
lines changed

2 files changed

+28
-32
lines changed

src/openai/lib/_parsing/_completions.py

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -138,30 +138,30 @@ def parse_chat_completion(
138138

139139
choices.append(
140140
construct_type_unchecked(
141-
type_=cast(Any, ParsedChoice)[solve_response_format_t(response_format)],
141+
type_=ParsedChoice[ResponseFormatT],
142142
value={
143143
**choice.to_dict(),
144-
"message": {
145-
**message.to_dict(),
146-
"parsed": maybe_parse_content(
147-
response_format=response_format,
148-
message=message,
149-
),
150-
"tool_calls": tool_calls if tool_calls else None,
151-
},
144+
"message": construct_type_unchecked(
145+
type_=ParsedChatCompletionMessage[ResponseFormatT],
146+
value={
147+
**message.to_dict(),
148+
"parsed": maybe_parse_content(
149+
response_format=response_format,
150+
message=message,
151+
),
152+
"tool_calls": tool_calls if tool_calls else None,
153+
},
154+
),
152155
},
153156
)
154157
)
155158

156-
return cast(
157-
ParsedChatCompletion[ResponseFormatT],
158-
construct_type_unchecked(
159-
type_=cast(Any, ParsedChatCompletion)[solve_response_format_t(response_format)],
160-
value={
161-
**chat_completion.to_dict(),
162-
"choices": choices,
163-
},
164-
),
159+
return construct_type_unchecked(
160+
type_=ParsedChatCompletion[ResponseFormatT],
161+
value={
162+
**chat_completion.to_dict(),
163+
"choices": choices,
164+
},
165165
)
166166

167167

src/openai/lib/_parsing/_responses.py

Lines changed: 10 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
from __future__ import annotations
22

33
import json
4-
from typing import TYPE_CHECKING, Any, List, Iterable, cast
4+
from typing import TYPE_CHECKING, List, Iterable, cast
55
from typing_extensions import TypeVar, assert_never
66

77
import pydantic
@@ -12,7 +12,7 @@
1212
from ..._compat import PYDANTIC_V1, model_parse_json
1313
from ..._models import construct_type_unchecked
1414
from .._pydantic import is_basemodel_type, is_dataclass_like_type
15-
from ._completions import solve_response_format_t, type_to_response_format_param
15+
from ._completions import type_to_response_format_param
1616
from ...types.responses import (
1717
Response,
1818
ToolParam,
@@ -56,7 +56,6 @@ def parse_response(
5656
input_tools: Iterable[ToolParam] | Omit | None,
5757
response: Response | ParsedResponse[object],
5858
) -> ParsedResponse[TextFormatT]:
59-
solved_t = solve_response_format_t(text_format)
6059
output_list: List[ParsedResponseOutputItem[TextFormatT]] = []
6160

6261
for output in response.output:
@@ -69,7 +68,7 @@ def parse_response(
6968

7069
content_list.append(
7170
construct_type_unchecked(
72-
type_=cast(Any, ParsedResponseOutputText)[solved_t],
71+
type_=ParsedResponseOutputText[TextFormatT],
7372
value={
7473
**item.to_dict(),
7574
"parsed": parse_text(item.text, text_format=text_format),
@@ -79,7 +78,7 @@ def parse_response(
7978

8079
output_list.append(
8180
construct_type_unchecked(
82-
type_=cast(Any, ParsedResponseOutputMessage)[solved_t],
81+
type_=ParsedResponseOutputMessage[TextFormatT],
8382
value={
8483
**output.to_dict(),
8584
"content": content_list,
@@ -123,15 +122,12 @@ def parse_response(
123122
else:
124123
output_list.append(output)
125124

126-
return cast(
127-
ParsedResponse[TextFormatT],
128-
construct_type_unchecked(
129-
type_=cast(Any, ParsedResponse)[solved_t],
130-
value={
131-
**response.to_dict(),
132-
"output": output_list,
133-
},
134-
),
125+
return construct_type_unchecked(
126+
type_=ParsedResponse[TextFormatT],
127+
value={
128+
**response.to_dict(),
129+
"output": output_list,
130+
},
135131
)
136132

137133

0 commit comments

Comments
 (0)