Skip to content

Commit a389776

Browse files
committed
fix(structured outputs): resolve memory leak in parse methods
1 parent bcb75a8 commit a389776

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
@@ -142,30 +142,30 @@ def parse_chat_completion(
142142

143143
choices.append(
144144
construct_type_unchecked(
145-
type_=cast(Any, ParsedChoice)[solve_response_format_t(response_format)],
145+
type_=ParsedChoice[ResponseFormatT],
146146
value={
147147
**choice.to_dict(),
148-
"message": {
149-
**message.to_dict(),
150-
"parsed": maybe_parse_content(
151-
response_format=response_format,
152-
message=message,
153-
),
154-
"tool_calls": tool_calls if tool_calls else None,
155-
},
148+
"message": construct_type_unchecked(
149+
type_=ParsedChatCompletionMessage[ResponseFormatT],
150+
value={
151+
**message.to_dict(),
152+
"parsed": maybe_parse_content(
153+
response_format=response_format,
154+
message=message,
155+
),
156+
"tool_calls": tool_calls if tool_calls else None,
157+
},
158+
),
156159
},
157160
)
158161
)
159162

160-
return cast(
161-
ParsedChatCompletion[ResponseFormatT],
162-
construct_type_unchecked(
163-
type_=cast(Any, ParsedChatCompletion)[solve_response_format_t(response_format)],
164-
value={
165-
**chat_completion.to_dict(),
166-
"choices": choices,
167-
},
168-
),
163+
return construct_type_unchecked(
164+
type_=ParsedChatCompletion[ResponseFormatT],
165+
value={
166+
**chat_completion.to_dict(),
167+
"choices": choices,
168+
},
169169
)
170170

171171

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,
@@ -118,15 +117,12 @@ def parse_response(
118117
else:
119118
output_list.append(output)
120119

121-
return cast(
122-
ParsedResponse[TextFormatT],
123-
construct_type_unchecked(
124-
type_=cast(Any, ParsedResponse)[solved_t],
125-
value={
126-
**response.to_dict(),
127-
"output": output_list,
128-
},
129-
),
120+
return construct_type_unchecked(
121+
type_=ParsedResponse[TextFormatT],
122+
value={
123+
**response.to_dict(),
124+
"output": output_list,
125+
},
130126
)
131127

132128

0 commit comments

Comments
 (0)