openai/openai-python

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v1.40.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

tests/lib/chat/test_completions.py

633lines · 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-9tABLlmqdEOYnmmWATUI3dNKlfXa3", "object": "chat.completion", "created": 1722934207, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "I\'m unable to provide real-time weather updates. For the current weather in San Francisco, I recommend checking a reliable weather website or app.", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 14, "completion_tokens": 27, "total_tokens": 41}, "system_fingerprint": "fp_e1a05a1dce"}'
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. For the current weather in San Francisco, I
60recommend checking 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=1722934207,
70 id='chatcmpl-9tABLlmqdEOYnmmWATUI3dNKlfXa3',
71 model='gpt-4o-2024-08-06',
72 object='chat.completion',
73 service_tier=None,
74 system_fingerprint='fp_e1a05a1dce',
75 usage=CompletionUsage(completion_tokens=27, prompt_tokens=14, total_tokens=41)
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-9tABUwdw3Kbe3VPRnMofh9lJkFkLV", "object": "chat.completion", "created": 1722934216, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 14, "total_tokens": 31}, "system_fingerprint": "fp_e1a05a1dce"}'
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":65,"units":"f"}',
116 function_call=None,
117 parsed=Location(city='San Francisco', temperature=65.0, units='f'),
118 refusal=None,
119 role='assistant',
120 tool_calls=[]
121 )
122 )
123 ],
124 created=1722934216,
125 id='chatcmpl-9tABUwdw3Kbe3VPRnMofh9lJkFkLV',
126 model='gpt-4o-2024-08-06',
127 object='chat.completion',
128 service_tier=None,
129 system_fingerprint='fp_e1a05a1dce',
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-9tABVfBu4ZdyQFKe8RgsWsyL7UoIj", "object": "chat.completion", "created": 1722934217, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":58.0,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 1, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":61,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}, {"index": 2, "message": {"role": "assistant", "content": "{\\"city\\":\\"San Francisco\\",\\"temperature\\":65,\\"units\\":\\"f\\"}", "refusal": null}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 44, "total_tokens": 61}, "system_fingerprint": "fp_e1a05a1dce"}'
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.0,"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":61,"units":"f"}',
186 function_call=None,
187 parsed=Location(city='San Francisco', temperature=61.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":65,"units":"f"}',
199 function_call=None,
200 parsed=Location(city='San Francisco', temperature=65.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-9tABVRLORZbby5zZjZhyrUdDU1XhB", "object": "chat.completion", "created": 1722934217, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_VcgQcA1C047fQnXDG0PQXG7O", "type": "function", "function": {"name": "Query", "arguments": "{\\"table_name\\":\\"orders\\",\\"columns\\":[\\"id\\",\\"status\\",\\"expected_delivery_date\\",\\"delivered_at\\"],\\"conditions\\":[{\\"column\\":\\"ordered_at\\",\\"operator\\":\\"=\\",\\"value\\":\\"2022-05\\"},{\\"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": 85, "total_tokens": 280}, "system_fingerprint": "fp_e1a05a1dce"}'
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"],
248"conditions":[{"column":"ordered_at","operator":"=","value":"2022-05"},{"column":"status","operator":"=","value":"fulfil
249led"},{"column":"delivered_at","operator":">","value":{"column_name":"expected_delivery_date"}}],"order_by":"asc"}',
250 name='Query',
251 parsed_arguments=Query(
252 columns=[
253 <Column.id: 'id'>,
254 <Column.status: 'status'>,
255 <Column.expected_delivery_date: 'expected_delivery_date'>,
256 <Column.delivered_at: 'delivered_at'>
257 ],
258 conditions=[
259 Condition(column='ordered_at', operator=<Operator.eq: '='>, value='2022-05'),
260 Condition(column='status', operator=<Operator.eq: '='>, value='fulfilled'),
261 Condition(
262 column='delivered_at',
263 operator=<Operator.gt: '>'>,
264 value=DynamicValue(column_name='expected_delivery_date')
265 )
266 ],
267 order_by=<OrderBy.asc: 'asc'>,
268 table_name=<Table.orders: 'orders'>
269 )
270 ),
271 id='call_VcgQcA1C047fQnXDG0PQXG7O',
272 type='function'
273 )
274 ]
275 )
276)
277"""
278 )
279
280
281@pytest.mark.respx(base_url=base_url)
282def test_parse_max_tokens_reached(client: OpenAI, respx_mock: MockRouter) -> None:
283 class Location(BaseModel):
284 city: str
285 temperature: float
286 units: Literal["c", "f"]
287
288 with pytest.raises(openai.LengthFinishReasonError):
289 _make_snapshot_request(
290 lambda c: c.beta.chat.completions.parse(
291 model="gpt-4o-2024-08-06",
292 messages=[
293 {
294 "role": "user",
295 "content": "What's the weather like in SF?",
296 },
297 ],
298 max_tokens=1,
299 response_format=Location,
300 ),
301 content_snapshot=snapshot(
302 '{"id": "chatcmpl-9tABXbi3qast6oJvdaqQcK9C7k9fn", "object": "chat.completion", "created": 1722934219, "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_e1a05a1dce"}'
303 ),
304 mock_client=client,
305 respx_mock=respx_mock,
306 )
307
308
309@pytest.mark.respx(base_url=base_url)
310def test_parse_pydantic_model_refusal(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
311 class Location(BaseModel):
312 city: str
313 temperature: float
314 units: Literal["c", "f"]
315
316 completion = _make_snapshot_request(
317 lambda c: c.beta.chat.completions.parse(
318 model="gpt-4o-2024-08-06",
319 messages=[
320 {
321 "role": "user",
322 "content": "How do I make anthrax?",
323 },
324 ],
325 response_format=Location,
326 ),
327 content_snapshot=snapshot(
328 '{"id": "chatcmpl-9tABXJEffhEWxp24MeLxkDJCMtWmx", "object": "chat.completion", "created": 1722934219, "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."}, "logprobs": null, "finish_reason": "stop"}], "usage": {"prompt_tokens": 17, "completion_tokens": 12, "total_tokens": 29}, "system_fingerprint": "fp_e1a05a1dce"}'
329 ),
330 mock_client=client,
331 respx_mock=respx_mock,
332 )
333
334 assert print_obj(completion.choices, monkeypatch) == snapshot(
335 """\
336[
337 ParsedChoice[Location](
338 finish_reason='stop',
339 index=0,
340 logprobs=None,
341 message=ParsedChatCompletionMessage[Location](
342 content=None,
343 function_call=None,
344 parsed=None,
345 refusal="I'm very sorry, but I can't assist with that.",
346 role='assistant',
347 tool_calls=[]
348 )
349 )
350]
351"""
352 )
353
354
355@pytest.mark.respx(base_url=base_url)
356def test_parse_pydantic_tool(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
357 class GetWeatherArgs(BaseModel):
358 city: str
359 country: str
360 units: Literal["c", "f"] = "c"
361
362 completion = _make_snapshot_request(
363 lambda c: c.beta.chat.completions.parse(
364 model="gpt-4o-2024-08-06",
365 messages=[
366 {
367 "role": "user",
368 "content": "What's the weather like in Edinburgh?",
369 },
370 ],
371 tools=[
372 openai.pydantic_function_tool(GetWeatherArgs),
373 ],
374 ),
375 content_snapshot=snapshot(
376 '{"id": "chatcmpl-9tABgtKnF7Gbri4CmpOocmhg0UgBF", "object": "chat.completion", "created": 1722934228, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_9rqjEc1DQRADTYGVV45LbZwL", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\":\\"Edinburgh\\",\\"country\\":\\"UK\\",\\"units\\":\\"c\\"}"}}], "refusal": null}, "logprobs": null, "finish_reason": "tool_calls"}], "usage": {"prompt_tokens": 76, "completion_tokens": 24, "total_tokens": 100}, "system_fingerprint": "fp_e1a05a1dce"}'
377 ),
378 mock_client=client,
379 respx_mock=respx_mock,
380 )
381
382 assert print_obj(completion.choices, monkeypatch) == snapshot(
383 """\
384[
385 ParsedChoice[NoneType](
386 finish_reason='tool_calls',
387 index=0,
388 logprobs=None,
389 message=ParsedChatCompletionMessage[NoneType](
390 content=None,
391 function_call=None,
392 parsed=None,
393 refusal=None,
394 role='assistant',
395 tool_calls=[
396 ParsedFunctionToolCall(
397 function=ParsedFunction(
398 arguments='{"city":"Edinburgh","country":"UK","units":"c"}',
399 name='GetWeatherArgs',
400 parsed_arguments=GetWeatherArgs(city='Edinburgh', country='UK', units='c')
401 ),
402 id='call_9rqjEc1DQRADTYGVV45LbZwL',
403 type='function'
404 )
405 ]
406 )
407 )
408]
409"""
410 )
411
412
413@pytest.mark.respx(base_url=base_url)
414def test_parse_multiple_pydantic_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
415 class GetWeatherArgs(BaseModel):
416 """Get the temperature for the given country/city combo"""
417
418 city: str
419 country: str
420 units: Literal["c", "f"] = "c"
421
422 class GetStockPrice(BaseModel):
423 ticker: str
424 exchange: str
425
426 completion = _make_snapshot_request(
427 lambda c: c.beta.chat.completions.parse(
428 model="gpt-4o-2024-08-06",
429 messages=[
430 {
431 "role": "user",
432 "content": "What's the weather like in Edinburgh?",
433 },
434 {
435 "role": "user",
436 "content": "What's the price of AAPL?",
437 },
438 ],
439 tools=[
440 openai.pydantic_function_tool(GetWeatherArgs),
441 openai.pydantic_function_tool(
442 GetStockPrice, name="get_stock_price", description="Fetch the latest price for a given ticker"
443 ),
444 ],
445 ),
446 content_snapshot=snapshot(
447 '{"id": "chatcmpl-9tABqDpvDTi0Cg8PHtKdNSFoh4UJv", "object": "chat.completion", "created": 1722934238, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_Yeg67XmQbMcohm3NGj0g12ty", "type": "function", "function": {"name": "GetWeatherArgs", "arguments": "{\\"city\\": \\"Edinburgh\\", \\"country\\": \\"GB\\", \\"units\\": \\"c\\"}"}}, {"id": "call_OGg3UZC2ksjAg7yrLXy8t1MO", "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_e1a05a1dce"}'
448 ),
449 mock_client=client,
450 respx_mock=respx_mock,
451 )
452
453 assert print_obj(completion.choices, monkeypatch) == snapshot(
454 """\
455[
456 ParsedChoice[NoneType](
457 finish_reason='tool_calls',
458 index=0,
459 logprobs=None,
460 message=ParsedChatCompletionMessage[NoneType](
461 content=None,
462 function_call=None,
463 parsed=None,
464 refusal=None,
465 role='assistant',
466 tool_calls=[
467 ParsedFunctionToolCall(
468 function=ParsedFunction(
469 arguments='{"city": "Edinburgh", "country": "GB", "units": "c"}',
470 name='GetWeatherArgs',
471 parsed_arguments=GetWeatherArgs(city='Edinburgh', country='GB', units='c')
472 ),
473 id='call_Yeg67XmQbMcohm3NGj0g12ty',
474 type='function'
475 ),
476 ParsedFunctionToolCall(
477 function=ParsedFunction(
478 arguments='{"ticker": "AAPL", "exchange": "NASDAQ"}',
479 name='get_stock_price',
480 parsed_arguments=GetStockPrice(exchange='NASDAQ', ticker='AAPL')
481 ),
482 id='call_OGg3UZC2ksjAg7yrLXy8t1MO',
483 type='function'
484 )
485 ]
486 )
487 )
488]
489"""
490 )
491
492
493@pytest.mark.respx(base_url=base_url)
494def test_parse_strict_tools(client: OpenAI, respx_mock: MockRouter, monkeypatch: pytest.MonkeyPatch) -> None:
495 completion = _make_snapshot_request(
496 lambda c: c.beta.chat.completions.parse(
497 model="gpt-4o-2024-08-06",
498 messages=[
499 {
500 "role": "user",
501 "content": "What's the weather like in SF?",
502 },
503 ],
504 tools=[
505 {
506 "type": "function",
507 "function": {
508 "name": "get_weather",
509 "parameters": {
510 "type": "object",
511 "properties": {
512 "city": {"type": "string"},
513 "state": {"type": "string"},
514 },
515 "required": [
516 "city",
517 "state",
518 ],
519 "additionalProperties": False,
520 },
521 "strict": True,
522 },
523 }
524 ],
525 ),
526 content_snapshot=snapshot(
527 '{"id": "chatcmpl-9tAC0vDx3MfupXmsduSZavLVaLcrA", "object": "chat.completion", "created": 1722934248, "model": "gpt-4o-2024-08-06", "choices": [{"index": 0, "message": {"role": "assistant", "content": null, "tool_calls": [{"id": "call_iNznvWR4R81mizFFHjgh7o4i", "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_e1a05a1dce"}'
528 ),
529 mock_client=client,
530 respx_mock=respx_mock,
531 )
532
533 assert print_obj(completion.choices, monkeypatch) == snapshot(
534 """\
535[
536 ParsedChoice[NoneType](
537 finish_reason='tool_calls',
538 index=0,
539 logprobs=None,
540 message=ParsedChatCompletionMessage[NoneType](
541 content=None,
542 function_call=None,
543 parsed=None,
544 refusal=None,
545 role='assistant',
546 tool_calls=[
547 ParsedFunctionToolCall(
548 function=ParsedFunction(
549 arguments='{"city":"San Francisco","state":"CA"}',
550 name='get_weather',
551 parsed_arguments={'city': 'San Francisco', 'state': 'CA'}
552 ),
553 id='call_iNznvWR4R81mizFFHjgh7o4i',
554 type='function'
555 )
556 ]
557 )
558 )
559]
560"""
561 )
562
563
564def test_parse_non_strict_tools(client: OpenAI) -> None:
565 with pytest.raises(
566 ValueError, match="`get_weather` is not strict. Only `strict` function tools can be auto-parsed"
567 ):
568 client.beta.chat.completions.parse(
569 model="gpt-4o-2024-08-06",
570 messages=[],
571 tools=[
572 {
573 "type": "function",
574 "function": {
575 "name": "get_weather",
576 "parameters": {},
577 },
578 }
579 ],
580 )
581
582
583@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"])
584def test_parse_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None:
585 checking_client: OpenAI | AsyncOpenAI = client if sync else async_client
586
587 assert_signatures_in_sync(
588 checking_client.chat.completions.create,
589 checking_client.beta.chat.completions.parse,
590 exclude_params={"response_format", "stream"},
591 )
592
593
594def _make_snapshot_request(
595 func: Callable[[OpenAI], _T],
596 *,
597 content_snapshot: Any,
598 respx_mock: MockRouter,
599 mock_client: OpenAI,
600) -> _T:
601 live = os.environ.get("OPENAI_LIVE") == "1"
602 if live:
603
604 def _on_response(response: httpx.Response) -> None:
605 # update the content snapshot
606 assert json.dumps(json.loads(response.read())) == content_snapshot
607
608 respx_mock.stop()
609
610 client = OpenAI(
611 http_client=httpx.Client(
612 event_hooks={
613 "response": [_on_response],
614 }
615 )
616 )
617 else:
618 respx_mock.post("/chat/completions").mock(
619 return_value=httpx.Response(
620 200,
621 content=content_snapshot._old_value,
622 headers={"content-type": "application/json"},
623 )
624 )
625
626 client = mock_client
627
628 result = func(client)
629
630 if live:
631 client.close()
632
633 return result
634