openai/openai-python

Public

mirrored from https://github.com/openai/openai-pythonAvailable

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.40.3

Branches

Tags

  • No tags available.
0Branches0Tags
Go to file
Add file
Code

Clone

HTTPS

Download ZIP

tests/lib/chat/test_completions.py

637lines · modecode

1from __future__ import annotations
2
3import os
4import json
5from typing import Any, Callable
6from typing_extensions import Literal, TypeVar
7
8import httpx
9import pytest
10from respx import MockRouter
11from pydantic import BaseModel
12from inline_snapshot import snapshot
13
14import openai
15from openai import OpenAI, AsyncOpenAI
16from openai._utils import assert_signatures_in_sync
17
18from ._utils import print_obj
19from ...conftest import base_url
20from ..schema_types.query import Query
21
22_T = TypeVar("_T")
23
24# all the snapshots in this file are auto-generated from the live API
25#
26# you can update them with
27#
28# `OPENAI_LIVE=1 pytest --inline-snapshot=fix`
29
30
31@pytest.mark.respx(base_url=base_url)
32def test_parse_nothing(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
33 completion = _make_snapshot_request(
34 lambda c: c.beta.chat.completions.parse(
35 model="gpt-4o-2024-08-06",
36 messages=[
37 {
38 "role": "user",
39 "content": "What's the weather like in SF?",
40 },
41 ],
42 ),
43 content_snapshot=snapshot(
44 '{"id": "chatcmpl-9tXjSozlYq8oGdlRH3vgLsiUNRg8c", "object": "chat.completion", "created": 1723024734, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "I\'m unable to provide real-time weather updates. To find out the current weather in San Francisco, please check a reliable weather website or app.", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 14, "completion_tokens": 28, "total_tokens": 42}, "system_fingerprint": "fp_845eaabc1f"}'
45 ),
46 mock_client=client,
47 respx_mock=respx_mock,
48 )
49
50 assert print_obj(completion, monkeypatch) == snapshot(
51 """\
52ParsedChatCompletion[NoneType](
53 choices=[
54 ParsedChoice[NoneType](
55 finish_reason='stop',
56 index=0,
57 logprobs=None,
58 message=ParsedChatCompletionMessage[NoneType](
59 content="I'm unable to provide real-time weather updates. To find out the current weather in San
60Francisco, please check a reliable weather website or app.",
61 function_call=None,
62 parsed=None,
63 refusal=None,
64 role='assistant',
65 tool_calls=[]
66 )
67 )
68 ],
69 created=1723024734,
70 id='chatcmpl-9tXjSozlYq8oGdlRH3vgLsiUNRg8c',
71 model='gpt-4o-2024-08-06',
72 object='chat.completion',
73 service_tier=None,
74 system_fingerprint='fp_845eaabc1f',
75 usage=CompletionUsage(completion_tokens=28, prompt_tokens=14, total_tokens=42)
76)
77"""
78 )
79
80
81@pytest.mark.respx(base_url=base_url)
82def test_parse_pydantic_model(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
83 class Location(BaseModel):
84 city: str
85 temperature: float
86 units: Literal["c", "f"]
87
88 completion = _make_snapshot_request(
89 lambda c: c.beta.chat.completions.parse(
90 model="gpt-4o-2024-08-06",
91 messages=[
92 {
93 "role": "user",
94 "content": "What's the weather like in SF?",
95 },
96 ],
97 response_format=Location,
98 ),
99 content_snapshot=snapshot(
100 '{"id": "chatcmpl-9tXjTNupyDe7nL1Z8eOO6BdSyrHAD", "object": "chat.completion", "created": 1723024735, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":56,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 14, "total_tokens": 31}, "system_fingerprint": "fp_2a322c9ffc"}'
101 ),
102 mock_client=client,
103 respx_mock=respx_mock,
104 )
105
106 assert print_obj(completion, monkeypatch) == snapshot(
107 """\
108ParsedChatCompletion[Location](
109 choices=[
110 ParsedChoice[Location](
111 finish_reason='stop',
112 index=0,
113 logprobs=None,
114 message=ParsedChatCompletionMessage[Location](
115 content='{"city":"San Francisco","temperature":56,"units":"f"}',
116 function_call=None,
117 parsed=Location(city='San Francisco', temperature=56.0, units='f'),
118 refusal=None,
119 role='assistant',
120 tool_calls=[]
121 )
122 )
123 ],
124 created=1723024735,
125 id='chatcmpl-9tXjTNupyDe7nL1Z8eOO6BdSyrHAD',
126 model='gpt-4o-2024-08-06',
127 object='chat.completion',
128 service_tier=None,
129 system_fingerprint='fp_2a322c9ffc',
130 usage=CompletionUsage(completion_tokens=14, prompt_tokens=17, total_tokens=31)
131)
132"""
133 )
134
135
136@pytest.mark.respx(base_url=base_url)
137def test_parse_pydantic_model_multiple_choices(
138 client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch
139) -> None:
140 class Location(BaseModel):
141 city: str
142 temperature: float
143 units: Literal["c", "f"]
144
145 completion = _make_snapshot_request(
146 lambda c: c.beta.chat.completions.parse(
147 model="gpt-4o-2024-08-06",
148 messages=[
149 {
150 "role": "user",
151 "content": "What's the weather like in SF?",
152 },
153 ],
154 n=3,
155 response_format=Location,
156 ),
157 content_snapshot=snapshot(
158 '{"id": "chatcmpl-9tXjUrNFyyjSB2FJ842TMDNRM6Gen", "object": "chat.completion", "created": 1723024736, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 1, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 2, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":63,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 42, "total_tokens": 59}, "system_fingerprint": "fp_845eaabc1f"}'
159 ),
160 mock_client=client,
161 respx_mock=respx_mock,
162 )
163
164 assert print_obj(completion.choices, monkeypatch) == snapshot(
165 """\
166[
167 ParsedChoice[Location](
168 finish_reason='stop',
169 index=0,
170 logprobs=None,
171 message=ParsedChatCompletionMessage[Location](
172 content='{"city":"San Francisco","temperature":58,"units":"f"}',
173 function_call=None,
174 parsed=Location(city='San Francisco', temperature=58.0, units='f'),
175 refusal=None,
176 role='assistant',
177 tool_calls=[]
178 )
179 ),
180 ParsedChoice[Location](
181 finish_reason='stop',
182 index=1,
183 logprobs=None,
184 message=ParsedChatCompletionMessage[Location](
185 content='{"city":"San Francisco","temperature":58,"units":"f"}',
186 function_call=None,
187 parsed=Location(city='San Francisco', temperature=58.0, units='f'),
188 refusal=None,
189 role='assistant',
190 tool_calls=[]
191 )
192 ),
193 ParsedChoice[Location](
194 finish_reason='stop',
195 index=2,
196 logprobs=None,
197 message=ParsedChatCompletionMessage[Location](
198 content='{"city":"San Francisco","temperature":63,"units":"f"}',
199 function_call=None,
200 parsed=Location(city='San Francisco', temperature=63.0, units='f'),
201 refusal=None,
202 role='assistant',
203 tool_calls=[]
204 )
205 )
206]
207"""
208 )
209
210
211@pytest.mark.respx(base_url=base_url)
212def test_pydantic_tool_model_all_types(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
213 completion = _make_snapshot_request(
214 lambda c: c.beta.chat.completions.parse(
215 model="gpt-4o-2024-08-06",
216 messages=[
217 {
218 "role": "user",
219 "content": "look up all my orders in may of last year that were fulfilled but not delivered on time",
220 },
221 ],
222 tools=[openai.pydantic_function_tool(Query)],
223 response_format=Query,
224 ),
225 content_snapshot=snapshot(
226 '{"id": "chatcmpl-9tXjVJVCLTn7CWFhpjETixvvApCk3", "object": "chat.completion", "created": 1723024737, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_Un4g0IXeQGOyqKBS3zhqNCox", "type": "function", "function": {"name": "Query", "arguments": "{\\"table_name\\":\\"orders\\",\\"columns\\":[\\"id\\",\\"status\\",\\"expected_delivery_date\\",\\"delivered_at\\",\\"shipped_at\\",\\"ordered_at\\"],\\"conditions\\":[{\\"column\\":\\"ordered_at\\",\\"operator\\":\\">=\\",\\"value\\":\\"2022-05-01\\"},{\\"column\\":\\"ordered_at\\",\\"operator\\":\\"<=\\",\\"value\\":\\"2022-05-31\\"},{\\"column\\":\\"status\\",\\"operator\\":\\"=\\",\\"value\\":\\"fulfilled\\"},{\\"column\\":\\"delivered_at\\",\\"operator\\":\\">\\",\\"value\\":{\\"column_name\\":\\"expected_delivery_date\\"}}],\\"order_by\\":\\"asc\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 195, "completion_tokens": 114, "total_tokens": 309}, "system_fingerprint": "fp_845eaabc1f"}'
227 ),
228 mock_client=client,
229 respx_mock=respx_mock,
230 )
231
232 assert print_obj(completion.choices[0], monkeypatch) == snapshot(
233 """\
234ParsedChoice[Query](
235 finish_reason='tool_calls',
236 index=0,
237 logprobs=None,
238 message=ParsedChatCompletionMessage[Query](
239 content=None,
240 function_call=None,
241 parsed=None,
242 refusal=None,
243 role='assistant',
244 tool_calls=[
245 ParsedFunctionToolCall(
246 function=ParsedFunction(
247 arguments='{"table_name":"orders","columns":["id","status","expected_delivery_date","delivered_at","
248shipped_at","ordered_at"],"conditions":[{"column":"ordered_at","operator":">=","value":"2022-05-01"},{"column":"ordered_
249at","operator":"<=","value":"2022-05-31"},{"column":"status","operator":"=","value":"fulfilled"},{"column":"delivered_at
250","operator":">","value":{"column_name":"expected_delivery_date"}}],"order_by":"asc"}',
251 name='Query',
252 parsed_arguments=Query(
253 columns=[
254 <Column.id: 'id'>,
255 <Column.status: 'status'>,
256 <Column.expected_delivery_date: 'expected_delivery_date'>,
257 <Column.delivered_at: 'delivered_at'>,
258 <Column.shipped_at: 'shipped_at'>,
259 <Column.ordered_at: 'ordered_at'>
260 ],
261 conditions=[
262 Condition(column='ordered_at', operator=<Operator.ge: '>='>, value='2022-05-01'),
263 Condition(column='ordered_at', operator=<Operator.le: '<='>, value='2022-05-31'),
264 Condition(column='status', operator=<Operator.eq: '='>, value='fulfilled'),
265 Condition(
266 column='delivered_at',
267 operator=<Operator.gt: '>'>,
268 value=DynamicValue(column_name='expected_delivery_date')
269 )
270 ],
271 order_by=<OrderBy.asc: 'asc'>,
272 table_name=<Table.orders: 'orders'>
273 )
274 ),
275 id='call_Un4g0IXeQGOyqKBS3zhqNCox',
276 type='function'
277 )
278 ]
279 )
280)
281"""
282 )
283
284
285@pytest.mark.respx(base_url=base_url)
286def test_parse_max_tokens_reached(client: OpenAI, respx_mock: MockRouter) -> None:
287 class Location(BaseModel):
288 city: str
289 temperature: float
290 units: Literal["c", "f"]
291
292 with pytest.raises(openai.LengthFinishReasonError):
293 _make_snapshot_request(
294 lambda c: c.beta.chat.completions.parse(
295 model="gpt-4o-2024-08-06",
296 messages=[
297 {
298 "role": "user",
299 "content": "What's the weather like in SF?",
300 },
301 ],
302 max_tokens=1,
303 response_format=Location,
304 ),
305 content_snapshot=snapshot(
306 '{"id": "chatcmpl-9tXjYACgVKixKdMv2nVQqDVELkdSF", "object": "chat.completion", "created": 1723024740, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"", "refusal": null}, "logprobs": null, "finish_reason": "length"}], "usage": {"prompt_tokens": 17, "completion_tokens": 1, "total_tokens": 18}, "system_fingerprint": "fp_2a322c9ffc"}'
307 ),
308 mock_client=client,
309 respx_mock=respx_mock,
310 )
311
312
313@pytest.mark.respx(base_url=base_url)
314def test_parse_pydantic_model_refusal(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
315 class Location(BaseModel):
316 city: str
317 temperature: float
318 units: Literal["c", "f"]
319
320 completion = _make_snapshot_request(
321 lambda c: c.beta.chat.completions.parse(
322 model="gpt-4o-2024-08-06",
323 messages=[
324 {
325 "role": "user",
326 "content": "How do I make anthrax?",
327 },
328 ],
329 response_format=Location,
330 ),
331 content_snapshot=snapshot(
332 '{"id": "chatcmpl-9tXm7FnIj3hSot5xM4c954MIePle0", "object": "chat.completion", "created": 1723024899, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "refusal": "I\'m very sorry, but I can\'t assist with that request."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 13, "total_tokens": 30}, "system_fingerprint": "fp_845eaabc1f"}'
333 ),
334 mock_client=client,
335 respx_mock=respx_mock,
336 )
337
338 assert print_obj(completion.choices, monkeypatch) == snapshot(
339 """\
340[
341 ParsedChoice[Location](
342 finish_reason='stop',
343 index=0,
344 logprobs=None,
345 message=ParsedChatCompletionMessage[Location](
346 content=None,
347 function_call=None,
348 parsed=None,
349 refusal="I'm very sorry, but I can't assist with that request.",
350 role='assistant',
351 tool_calls=[]
352 )
353 )
354]
355"""
356 )
357
358
359@pytest.mark.respx(base_url=base_url)
360def test_parse_pydantic_tool(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
361 class GetWeatherArgs(BaseModel):
362 city: str
363 country: str
364 units: Literal["c", "f"] = "c"
365
366 completion = _make_snapshot_request(
367 lambda c: c.beta.chat.completions.parse(
368 model="gpt-4o-2024-08-06",
369 messages=[
370 {
371 "role": "user",
372 "content": "What's the weather like in Edinburgh?",
373 },
374 ],
375 tools=[
376 openai.pydantic_function_tool(GetWeatherArgs),
377 ],
378 ),
379 content_snapshot=snapshot(
380 '{"id": "chatcmpl-9tXjbQ9V0l5XPlynOJHKvrWsJQymO", "object": "chat.completion", "created": 1723024743, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_EEaIYq8aTdiDWro8jILNl3XK", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\":\\"Edinburgh\\",\\"country\\":\\"GB\\",\\"units\\":\\"c\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 76, "completion_tokens": 24, "total_tokens": 100}, "system_fingerprint": "fp_2a322c9ffc"}'
381 ),
382 mock_client=client,
383 respx_mock=respx_mock,
384 )
385
386 assert print_obj(completion.choices, monkeypatch) == snapshot(
387 """\
388[
389 ParsedChoice[NoneType](
390 finish_reason='tool_calls',
391 index=0,
392 logprobs=None,
393 message=ParsedChatCompletionMessage[NoneType](
394 content=None,
395 function_call=None,
396 parsed=None,
397 refusal=None,
398 role='assistant',
399 tool_calls=[
400 ParsedFunctionToolCall(
401 function=ParsedFunction(
402 arguments='{"city":"Edinburgh","country":"GB","units":"c"}',
403 name='GetWeatherArgs',
404 parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c')
405 ),
406 id='call_EEaIYq8aTdiDWro8jILNl3XK',
407 type='function'
408 )
409 ]
410 )
411 )
412]
413"""
414 )
415
416
417@pytest.mark.respx(base_url=base_url)
418def test_parse_multiple_pydantic_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
419 class GetWeatherArgs(BaseModel):
420 """Get the temperature for the given country/city combo"""
421
422 city: str
423 country: str
424 units: Literal["c", "f"] = "c"
425
426 class GetStockPrice(BaseModel):
427 ticker: str
428 exchange: str
429
430 completion = _make_snapshot_request(
431 lambda c: c.beta.chat.completions.parse(
432 model="gpt-4o-2024-08-06",
433 messages=[
434 {
435 "role": "user",
436 "content": "What's the weather like in Edinburgh?",
437 },
438 {
439 "role": "user",
440 "content": "What's the price of AAPL?",
441 },
442 ],
443 tools=[
444 openai.pydantic_function_tool(GetWeatherArgs),
445 openai.pydantic_function_tool(
446 GetStockPrice, name="get_stock_price", description="Fetch the latest price for a given ticker"
447 ),
448 ],
449 ),
450 content_snapshot=snapshot(
451 '{"id": "chatcmpl-9tXjcnIvzZDXRfLfbVTPNL5963GWw", "object": "chat.completion", "created": 1723024744, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_ECSuZ8gcNPPwgt24me91jHsJ", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\": \\"Edinburgh\\", \\"country\\": \\"UK\\", \\"units\\": \\"c\\"}"}}, {"id": "call_Z3fM2sNBBGILhMtimk5Y3RQk", "type": "function", "function": {"name": "get_stock_price", "arguments": "{\\"ticker\\": \\"AAPL\\", \\"exchange\\": \\"NASDAQ\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 149, "completion_tokens": 60, "total_tokens": 209}, "system_fingerprint": "fp_845eaabc1f"}'
452 ),
453 mock_client=client,
454 respx_mock=respx_mock,
455 )
456
457 assert print_obj(completion.choices, monkeypatch) == snapshot(
458 """\
459[
460 ParsedChoice[NoneType](
461 finish_reason='tool_calls',
462 index=0,
463 logprobs=None,
464 message=ParsedChatCompletionMessage[NoneType](
465 content=None,
466 function_call=None,
467 parsed=None,
468 refusal=None,
469 role='assistant',
470 tool_calls=[
471 ParsedFunctionToolCall(
472 function=ParsedFunction(
473 arguments='{"city": "Edinburgh", "country": "UK", "units": "c"}',
474 name='GetWeatherArgs',
475 parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c')
476 ),
477 id='call_ECSuZ8gcNPPwgt24me91jHsJ',
478 type='function'
479 ),
480 ParsedFunctionToolCall(
481 function=ParsedFunction(
482 arguments='{"ticker": "AAPL", "exchange": "NASDAQ"}',
483 name='get_stock_price',
484 parsed_arguments=GetStockPrice(exchange='NASDAQ', ticker='AAPL')
485 ),
486 id='call_Z3fM2sNBBGILhMtimk5Y3RQk',
487 type='function'
488 )
489 ]
490 )
491 )
492]
493"""
494 )
495
496
497@pytest.mark.respx(base_url=base_url)
498def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
499 completion = _make_snapshot_request(
500 lambda c: c.beta.chat.completions.parse(
501 model="gpt-4o-2024-08-06",
502 messages=[
503 {
504 "role": "user",
505 "content": "What's the weather like in SF?",
506 },
507 ],
508 tools=[
509 {
510 "type": "function",
511 "function": {
512 "name": "get_weather",
513 "parameters": {
514 "type": "object",
515 "properties": {
516 "city": {"type": "string"},
517 "state": {"type": "string"},
518 },
519 "required": [
520 "city",
521 "state",
522 ],
523 "additionalProperties": False,
524 },
525 "strict": True,
526 },
527 }
528 ],
529 ),
530 content_snapshot=snapshot(
531 '{"id": "chatcmpl-9tXjfjETDIqeYvDjsuGACbwdY0xsr", "object": "chat.completion", "created": 1723024747, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_7ZZPctBXQWexQlIHSrIHMVUq", "type": "function", "function": {"name": "get_weather", "arguments": "{\\"city\\":\\"San Francisco\\",\\"state\\":\\"CA\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 48, "completion_tokens": 19, "total_tokens": 67}, "system_fingerprint": "fp_2a322c9ffc"}'
532 ),
533 mock_client=client,
534 respx_mock=respx_mock,
535 )
536
537 assert print_obj(completion.choices, monkeypatch) == snapshot(
538 """\
539[
540 ParsedChoice[NoneType](
541 finish_reason='tool_calls',
542 index=0,
543 logprobs=None,
544 message=ParsedChatCompletionMessage[NoneType](
545 content=None,
546 function_call=None,
547 parsed=None,
548 refusal=None,
549 role='assistant',
550 tool_calls=[
551 ParsedFunctionToolCall(
552 function=ParsedFunction(
553 arguments='{"city":"San Francisco","state":"CA"}',
554 name='get_weather',
555 parsed_arguments={'city': 'San Francisco', 'state': 'CA'}
556 ),
557 id='call_7ZZPctBXQWexQlIHSrIHMVUq',
558 type='function'
559 )
560 ]
561 )
562 )
563]
564"""
565 )
566
567
568def test_parse_non_strict_tools(client: OpenAI) -> None:
569 with pytest.raises(
570 ValueError, match="`get_weather` is not strict. Only `strict` function tools can be auto-parsed"
571 ):
572 client.beta.chat.completions.parse(
573 model="gpt-4o-2024-08-06",
574 messages=[],
575 tools=[
576 {
577 "type": "function",
578 "function": {
579 "name": "get_weather",
580 "parameters": {},
581 },
582 }
583 ],
584 )
585
586
587@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"])
588def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None:
589 checking_client: OpenAI | AsyncOpenAI = client if sync else async_client
590
591 assert_signatures_in_sync(
592 checking_client.chat.completions.create,
593 checking_client.beta.chat.completions.parse,
594 exclude_params={"response_format", "stream"},
595 )
596
597
598def _make_snapshot_request(
599 func: Callable[[OpenAI], _T],
600 *,
601 content_snapshot: Any,
602 respx_mock: MockRouter,
603 mock_client: OpenAI,
604) -> _T:
605 live = os.environ.get("OPENAI_LIVE") == "1"
606 if live:
607
608 def _on_response(response: httpx.Response) -> None:
609 # update the content snapshot
610 assert json.dumps(json.loads(response.read())) == content_snapshot
611
612 respx_mock.stop()
613
614 client = OpenAI(
615 http_client=httpx.Client(
616 event_hooks={
617 "response": [_on_response],
618 }
619 )
620 )
621 else:
622 respx_mock.post("/chat/completions").mock(
623 return_value=httpx.Response(
624 200,
625 content=content_snapshot._old_value,
626 headers={"content-type": "application/json"},
627 )
628 )
629
630 client = mock_client
631
632 result = func(client)
633
634 if live:
635 client.close()
636
637 return result
638