openai/openai-python

Public

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

CodeCommitsIssuesPull requestsActionsInsightsSecurity
v2.38.0

Branches

Tags

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

Clone

HTTPS

Download ZIP

tests/lib/test_azure.py

955lines · modeblame

c98d7400Krista Pratico1 years ago1from __future__ import annotations
2
1ca831cfKrista Pratico1 years ago3import logging
6b01ba6aRobert Craigie1 years ago4from typing import Union, cast
5from typing_extensions import Literal, Protocol
08b8179aDavid Schnurr2 years ago6
6b01ba6aRobert Craigie1 years ago7import httpx
08b8179aDavid Schnurr2 years ago8import pytest
6b01ba6aRobert Craigie1 years ago9from respx import MockRouter
08b8179aDavid Schnurr2 years ago10
c99535c7Alex Chang1 months ago11from openai import OpenAIError
12from tests.utils import update_env
13from openai._types import Omit
1ca831cfKrista Pratico1 years ago14from openai._utils import SensitiveHeadersFilter, is_dict
08b8179aDavid Schnurr2 years ago15from openai._models import FinalRequestOptions
16from openai.lib.azure import AzureOpenAI, AsyncAzureOpenAI
17
18Client = Union[AzureOpenAI, AsyncAzureOpenAI]
19
20
21sync_client = AzureOpenAI(
22api_version="2023-07-01",
23api_key="example API key",
24azure_endpoint="https://example-resource.azure.openai.com",
25)
26
27async_client = AsyncAzureOpenAI(
28api_version="2023-07-01",
29api_key="example API key",
30azure_endpoint="https://example-resource.azure.openai.com",
31)
32
33
6b01ba6aRobert Craigie1 years ago34class MockRequestCall(Protocol):
35request: httpx.Request
36
37
08b8179aDavid Schnurr2 years ago38@pytest.mark.parametrize("client", [sync_client, async_client])
39def test_implicit_deployment_path(client: Client) -> None:
40req = client._build_request(
41FinalRequestOptions.construct(
42method="post",
43url="/chat/completions",
44json_data={"model": "my-deployment-model"},
45)
46)
47assert (
48req.url
49== "https://example-resource.azure.openai.com/openai/deployments/my-deployment-model/chat/completions?api-version=2023-07-01"
50)
97a6895bStainless Bot2 years ago51
52
53@pytest.mark.parametrize(
54"client,method",
55[
56(sync_client, "copy"),
57(sync_client, "with_options"),
58(async_client, "copy"),
59(async_client, "with_options"),
60],
61)
62def test_client_copying(client: Client, method: Literal["copy", "with_options"]) -> None:
63if method == "copy":
64copied = client.copy()
65else:
66copied = client.with_options()
67
68assert copied._custom_query == {"api-version": "2023-07-01"}
69
70
71@pytest.mark.parametrize(
72"client",
73[sync_client, async_client],
74)
75def test_client_copying_override_options(client: Client) -> None:
76copied = client.copy(
77api_version="2022-05-01",
78)
79assert copied._custom_query == {"api-version": "2022-05-01"}
6b01ba6aRobert Craigie1 years ago80
81
c99535c7Alex Chang1 months ago82def test_enforce_credentials_false_sync() -> None:
83with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
84AzureOpenAI(
85api_version="2024-02-01",
86api_key=None,
87azure_ad_token=None,
88azure_ad_token_provider=None,
89azure_endpoint="https://example-resource.azure.openai.com",
90_enforce_credentials=False,
91)
92
93
15a9e05aAlex Chang1 months ago94@pytest.mark.respx()
95def test_enforce_credentials_false_sync_uses_default_api_key_header(respx_mock: MockRouter) -> None:
96respx_mock.post(
97"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
98).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
99
100with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
101client = AzureOpenAI(
102api_version="2024-02-01",
103api_key=None,
104azure_ad_token=None,
105azure_ad_token_provider=None,
106azure_endpoint="https://example-resource.azure.openai.com",
107default_headers={"api-key": "manual-api-key"},
108_enforce_credentials=False,
109)
110client.chat.completions.create(messages=[], model="gpt-4")
111
112calls = cast("list[MockRequestCall]", respx_mock.calls)
113assert calls[0].request.headers.get("api-key") == "manual-api-key"
114assert calls[0].request.headers.get("Authorization") is None
115
116
117@pytest.mark.respx()
118def test_enforce_credentials_false_sync_uses_request_authorization_header(respx_mock: MockRouter) -> None:
119respx_mock.post(
120"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
121).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
122
123with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
124client = AzureOpenAI(
125api_version="2024-02-01",
126api_key=None,
127azure_ad_token=None,
128azure_ad_token_provider=None,
129azure_endpoint="https://example-resource.azure.openai.com",
130_enforce_credentials=False,
131)
132client.chat.completions.create(
133messages=[],
134model="gpt-4",
135extra_headers={"authorization": "Bearer manual-token"},
136)
137
138calls = cast("list[MockRequestCall]", respx_mock.calls)
139assert calls[0].request.headers.get("Authorization") == "Bearer manual-token"
140assert calls[0].request.headers.get("api-key") is None
141
142
c99535c7Alex Chang1 months ago143def test_enforce_credentials_true_sync() -> None:
144with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
145with pytest.raises(OpenAIError, match="Missing credentials"):
146AzureOpenAI(
147api_version="2024-02-01",
148api_key=None,
149azure_ad_token=None,
150azure_ad_token_provider=None,
151azure_endpoint="https://example-resource.azure.openai.com",
152)
153
154
155def test_enforce_credentials_false_async() -> None:
156with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
157AsyncAzureOpenAI(
158api_version="2024-02-01",
159api_key=None,
160azure_ad_token=None,
161azure_ad_token_provider=None,
162azure_endpoint="https://example-resource.azure.openai.com",
163_enforce_credentials=False,
164)
165
166
15a9e05aAlex Chang1 months ago167@pytest.mark.asyncio
168@pytest.mark.respx()
169async def test_enforce_credentials_false_async_uses_default_api_key_header(respx_mock: MockRouter) -> None:
170respx_mock.post(
171"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
172).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
173
174with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
175client = AsyncAzureOpenAI(
176api_version="2024-02-01",
177api_key=None,
178azure_ad_token=None,
179azure_ad_token_provider=None,
180azure_endpoint="https://example-resource.azure.openai.com",
181default_headers={"api-key": "manual-api-key"},
182_enforce_credentials=False,
183)
184await client.chat.completions.create(messages=[], model="gpt-4")
185
186calls = cast("list[MockRequestCall]", respx_mock.calls)
187assert calls[0].request.headers.get("api-key") == "manual-api-key"
188assert calls[0].request.headers.get("Authorization") is None
189
190
191@pytest.mark.asyncio
192@pytest.mark.respx()
193async def test_enforce_credentials_false_async_uses_request_authorization_header(respx_mock: MockRouter) -> None:
194respx_mock.post(
195"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
196).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
197
198with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
199client = AsyncAzureOpenAI(
200api_version="2024-02-01",
201api_key=None,
202azure_ad_token=None,
203azure_ad_token_provider=None,
204azure_endpoint="https://example-resource.azure.openai.com",
205_enforce_credentials=False,
206)
207await client.chat.completions.create(
208messages=[],
209model="gpt-4",
210extra_headers={"authorization": "Bearer manual-token"},
211)
212
213calls = cast("list[MockRequestCall]", respx_mock.calls)
214assert calls[0].request.headers.get("Authorization") == "Bearer manual-token"
215assert calls[0].request.headers.get("api-key") is None
216
217
c99535c7Alex Chang1 months ago218def test_enforce_credentials_true_async() -> None:
219with update_env(AZURE_OPENAI_API_KEY=Omit(), AZURE_OPENAI_AD_TOKEN=Omit()):
220with pytest.raises(OpenAIError, match="Missing credentials"):
221AsyncAzureOpenAI(
222api_version="2024-02-01",
223api_key=None,
224azure_ad_token=None,
225azure_ad_token_provider=None,
226azure_endpoint="https://example-resource.azure.openai.com",
227)
228
229
6b01ba6aRobert Craigie1 years ago230@pytest.mark.respx()
231def test_client_token_provider_refresh_sync(respx_mock: MockRouter) -> None:
232respx_mock.post(
233"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
234).mock(
235side_effect=[
236httpx.Response(500, json={"error": "server error"}),
237httpx.Response(200, json={"foo": "bar"}),
238]
239)
240
241counter = 0
242
243def token_provider() -> str:
244nonlocal counter
245
246counter += 1
247
248if counter == 1:
249return "first"
250
251return "second"
252
253client = AzureOpenAI(
254api_version="2024-02-01",
255azure_ad_token_provider=token_provider,
256azure_endpoint="https://example-resource.azure.openai.com",
257)
258client.chat.completions.create(messages=[], model="gpt-4")
259
260calls = cast("list[MockRequestCall]", respx_mock.calls)
261
262assert len(calls) == 2
263
264assert calls[0].request.headers.get("Authorization") == "Bearer first"
265assert calls[1].request.headers.get("Authorization") == "Bearer second"
266
267
268@pytest.mark.asyncio
269@pytest.mark.respx()
270async def test_client_token_provider_refresh_async(respx_mock: MockRouter) -> None:
271respx_mock.post(
272"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-02-01"
273).mock(
274side_effect=[
275httpx.Response(500, json={"error": "server error"}),
276httpx.Response(200, json={"foo": "bar"}),
277]
278)
279
280counter = 0
281
282def token_provider() -> str:
283nonlocal counter
284
285counter += 1
286
287if counter == 1:
288return "first"
289
290return "second"
291
292client = AsyncAzureOpenAI(
293api_version="2024-02-01",
294azure_ad_token_provider=token_provider,
295azure_endpoint="https://example-resource.azure.openai.com",
296)
297
298await client.chat.completions.create(messages=[], model="gpt-4")
299
300calls = cast("list[MockRequestCall]", respx_mock.calls)
301
302assert len(calls) == 2
303
304assert calls[0].request.headers.get("Authorization") == "Bearer first"
305assert calls[1].request.headers.get("Authorization") == "Bearer second"
1ca831cfKrista Pratico1 years ago306
307
308class TestAzureLogging:
309@pytest.fixture(autouse=True)
310def logger_with_filter(self) -> logging.Logger:
311logger = logging.getLogger("openai")
312logger.setLevel(logging.DEBUG)
313logger.addFilter(SensitiveHeadersFilter())
314return logger
315
316@pytest.mark.respx()
317def test_azure_api_key_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
318respx_mock.post(
319"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
300f58bbstainless-app[bot]1 years ago320).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
1ca831cfKrista Pratico1 years ago321
322client = AzureOpenAI(
323api_version="2024-06-01",
324api_key="example_api_key",
325azure_endpoint="https://example-resource.azure.openai.com",
326)
327
328with caplog.at_level(logging.DEBUG):
329client.chat.completions.create(messages=[], model="gpt-4")
330
331for record in caplog.records:
332if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]):
333assert record.args["headers"]["api-key"] == "<redacted>"
334
335@pytest.mark.respx()
336def test_azure_bearer_token_redacted(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
337respx_mock.post(
338"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
300f58bbstainless-app[bot]1 years ago339).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
1ca831cfKrista Pratico1 years ago340
341client = AzureOpenAI(
342api_version="2024-06-01",
343azure_ad_token="example_token",
344azure_endpoint="https://example-resource.azure.openai.com",
345)
346
347with caplog.at_level(logging.DEBUG):
348client.chat.completions.create(messages=[], model="gpt-4")
349
350for record in caplog.records:
351if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]):
352assert record.args["headers"]["Authorization"] == "<redacted>"
353
354@pytest.mark.asyncio
355@pytest.mark.respx()
356async def test_azure_api_key_redacted_async(self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture) -> None:
357respx_mock.post(
358"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
300f58bbstainless-app[bot]1 years ago359).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
1ca831cfKrista Pratico1 years ago360
361client = AsyncAzureOpenAI(
362api_version="2024-06-01",
363api_key="example_api_key",
364azure_endpoint="https://example-resource.azure.openai.com",
365)
366
367with caplog.at_level(logging.DEBUG):
368await client.chat.completions.create(messages=[], model="gpt-4")
369
370for record in caplog.records:
371if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]):
372assert record.args["headers"]["api-key"] == "<redacted>"
373
374@pytest.mark.asyncio
375@pytest.mark.respx()
300f58bbstainless-app[bot]1 years ago376async def test_azure_bearer_token_redacted_async(
377self, respx_mock: MockRouter, caplog: pytest.LogCaptureFixture
378) -> None:
1ca831cfKrista Pratico1 years ago379respx_mock.post(
380"https://example-resource.azure.openai.com/openai/deployments/gpt-4/chat/completions?api-version=2024-06-01"
300f58bbstainless-app[bot]1 years ago381).mock(return_value=httpx.Response(200, json={"model": "gpt-4"}))
1ca831cfKrista Pratico1 years ago382
383client = AsyncAzureOpenAI(
384api_version="2024-06-01",
385azure_ad_token="example_token",
386azure_endpoint="https://example-resource.azure.openai.com",
387)
388
389with caplog.at_level(logging.DEBUG):
390await client.chat.completions.create(messages=[], model="gpt-4")
391
392for record in caplog.records:
393if is_dict(record.args) and record.args.get("headers") and is_dict(record.args["headers"]):
394assert record.args["headers"]["Authorization"] == "<redacted>"
c98d7400Krista Pratico1 years ago395
396
397@pytest.mark.parametrize(
398"client,base_url,api,json_data,expected",
399[
400# Deployment-based endpoints
401# AzureOpenAI: No deployment specified
402(
403AzureOpenAI(
404api_version="2024-02-01",
405api_key="example API key",
406azure_endpoint="https://example-resource.azure.openai.com",
407),
408"https://example-resource.azure.openai.com/openai/",
409"/chat/completions",
410{"model": "deployment-body"},
411"https://example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01",
412),
413# AzureOpenAI: Deployment specified
414(
415AzureOpenAI(
416api_version="2024-02-01",
417api_key="example API key",
418azure_endpoint="https://example-resource.azure.openai.com",
419azure_deployment="deployment-client",
420),
421"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
422"/chat/completions",
423{"model": "deployment-body"},
424"https://example-resource.azure.openai.com/openai/deployments/deployment-client/chat/completions?api-version=2024-02-01",
425),
426# AzureOpenAI: "deployments" in the DNS name
427(
428AzureOpenAI(
429api_version="2024-02-01",
430api_key="example API key",
431azure_endpoint="https://deployments.example-resource.azure.openai.com",
432),
433"https://deployments.example-resource.azure.openai.com/openai/",
434"/chat/completions",
435{"model": "deployment-body"},
436"https://deployments.example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01",
437),
438# AzureOpenAI: Deployment called deployments
439(
440AzureOpenAI(
441api_version="2024-02-01",
442api_key="example API key",
443azure_endpoint="https://example-resource.azure.openai.com",
444azure_deployment="deployments",
445),
446"https://example-resource.azure.openai.com/openai/deployments/deployments/",
447"/chat/completions",
448{"model": "deployment-body"},
449"https://example-resource.azure.openai.com/openai/deployments/deployments/chat/completions?api-version=2024-02-01",
450),
451# AzureOpenAI: base_url and azure_deployment specified; ignored b/c not supported
452(
453AzureOpenAI( # type: ignore
454api_version="2024-02-01",
455api_key="example API key",
456base_url="https://example.azure-api.net/PTU/",
457azure_deployment="deployment-client",
458),
459"https://example.azure-api.net/PTU/",
460"/chat/completions",
461{"model": "deployment-body"},
462"https://example.azure-api.net/PTU/deployments/deployment-body/chat/completions?api-version=2024-02-01",
463),
464# AsyncAzureOpenAI: No deployment specified
465(
466AsyncAzureOpenAI(
467api_version="2024-02-01",
468api_key="example API key",
469azure_endpoint="https://example-resource.azure.openai.com",
470),
471"https://example-resource.azure.openai.com/openai/",
472"/chat/completions",
473{"model": "deployment-body"},
474"https://example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01",
475),
476# AsyncAzureOpenAI: Deployment specified
477(
478AsyncAzureOpenAI(
479api_version="2024-02-01",
480api_key="example API key",
481azure_endpoint="https://example-resource.azure.openai.com",
482azure_deployment="deployment-client",
483),
484"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
485"/chat/completions",
486{"model": "deployment-body"},
487"https://example-resource.azure.openai.com/openai/deployments/deployment-client/chat/completions?api-version=2024-02-01",
488),
489# AsyncAzureOpenAI: "deployments" in the DNS name
490(
491AsyncAzureOpenAI(
492api_version="2024-02-01",
493api_key="example API key",
494azure_endpoint="https://deployments.example-resource.azure.openai.com",
495),
496"https://deployments.example-resource.azure.openai.com/openai/",
497"/chat/completions",
498{"model": "deployment-body"},
499"https://deployments.example-resource.azure.openai.com/openai/deployments/deployment-body/chat/completions?api-version=2024-02-01",
500),
501# AsyncAzureOpenAI: Deployment called deployments
502(
503AsyncAzureOpenAI(
504api_version="2024-02-01",
505api_key="example API key",
506azure_endpoint="https://example-resource.azure.openai.com",
507azure_deployment="deployments",
508),
509"https://example-resource.azure.openai.com/openai/deployments/deployments/",
510"/chat/completions",
511{"model": "deployment-body"},
512"https://example-resource.azure.openai.com/openai/deployments/deployments/chat/completions?api-version=2024-02-01",
513),
514# AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported
515(
516AsyncAzureOpenAI( # type: ignore
517api_version="2024-02-01",
518api_key="example API key",
519base_url="https://example.azure-api.net/PTU/",
520azure_deployment="deployment-client",
521),
522"https://example.azure-api.net/PTU/",
523"/chat/completions",
524{"model": "deployment-body"},
525"https://example.azure-api.net/PTU/deployments/deployment-body/chat/completions?api-version=2024-02-01",
526),
527],
528)
529def test_prepare_url_deployment_endpoint(
530client: Client, base_url: str, api: str, json_data: dict[str, str], expected: str
531) -> None:
532req = client._build_request(
533FinalRequestOptions.construct(
534method="post",
535url=api,
536json_data=json_data,
537)
538)
539assert req.url == expected
540assert client.base_url == base_url
541
542
543@pytest.mark.parametrize(
544"client,base_url,api,json_data,expected",
545[
546# Non-deployment endpoints
547# AzureOpenAI: No deployment specified
548(
549AzureOpenAI(
550api_version="2024-02-01",
551api_key="example API key",
552azure_endpoint="https://example-resource.azure.openai.com",
553),
554"https://example-resource.azure.openai.com/openai/",
555"/models",
556{},
557"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
558),
559# AzureOpenAI: No deployment specified
560(
561AzureOpenAI(
562api_version="2024-02-01",
563api_key="example API key",
564azure_endpoint="https://example-resource.azure.openai.com",
565),
566"https://example-resource.azure.openai.com/openai/",
567"/assistants",
568{"model": "deployment-body"},
569"https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01",
570),
571# AzureOpenAI: Deployment specified
572(
573AzureOpenAI(
574api_version="2024-02-01",
575api_key="example API key",
576azure_endpoint="https://example-resource.azure.openai.com",
577azure_deployment="deployment-client",
578),
579"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
580"/models",
581{},
582"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
583),
584# AzureOpenAI: Deployment specified
585(
586AzureOpenAI(
587api_version="2024-02-01",
588api_key="example API key",
589azure_endpoint="https://example-resource.azure.openai.com",
590azure_deployment="deployment-client",
591),
592"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
593"/assistants",
594{"model": "deployment-body"},
595"https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01",
596),
597# AzureOpenAI: "deployments" in the DNS name
598(
599AzureOpenAI(
600api_version="2024-02-01",
601api_key="example API key",
602azure_endpoint="https://deployments.example-resource.azure.openai.com",
603),
604"https://deployments.example-resource.azure.openai.com/openai/",
605"/models",
606{},
607"https://deployments.example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
608),
609# AzureOpenAI: Deployment called "deployments"
610(
611AzureOpenAI(
612api_version="2024-02-01",
613api_key="example API key",
614azure_endpoint="https://example-resource.azure.openai.com",
615azure_deployment="deployments",
616),
617"https://example-resource.azure.openai.com/openai/deployments/deployments/",
618"/models",
619{},
620"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
621),
622# AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported
623(
624AzureOpenAI( # type: ignore
625api_version="2024-02-01",
626api_key="example API key",
627base_url="https://example.azure-api.net/PTU/",
628azure_deployment="deployment-client",
629),
630"https://example.azure-api.net/PTU/",
631"/models",
632{},
633"https://example.azure-api.net/PTU/models?api-version=2024-02-01",
634),
635# AsyncAzureOpenAI: No deployment specified
636(
637AsyncAzureOpenAI(
638api_version="2024-02-01",
639api_key="example API key",
640azure_endpoint="https://example-resource.azure.openai.com",
641),
642"https://example-resource.azure.openai.com/openai/",
643"/models",
644{},
645"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
646),
647# AsyncAzureOpenAI: No deployment specified
648(
649AsyncAzureOpenAI(
650api_version="2024-02-01",
651api_key="example API key",
652azure_endpoint="https://example-resource.azure.openai.com",
653),
654"https://example-resource.azure.openai.com/openai/",
655"/assistants",
656{"model": "deployment-body"},
657"https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01",
658),
659# AsyncAzureOpenAI: Deployment specified
660(
661AsyncAzureOpenAI(
662api_version="2024-02-01",
663api_key="example API key",
664azure_endpoint="https://example-resource.azure.openai.com",
665azure_deployment="deployment-client",
666),
667"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
668"/models",
669{},
670"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
671),
672# AsyncAzureOpenAI: Deployment specified
673(
674AsyncAzureOpenAI(
675api_version="2024-02-01",
676api_key="example API key",
677azure_endpoint="https://example-resource.azure.openai.com",
678azure_deployment="deployment-client",
679),
680"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
681"/assistants",
682{"model": "deployment-body"},
683"https://example-resource.azure.openai.com/openai/assistants?api-version=2024-02-01",
684),
685# AsyncAzureOpenAI: "deployments" in the DNS name
686(
687AsyncAzureOpenAI(
688api_version="2024-02-01",
689api_key="example API key",
690azure_endpoint="https://deployments.example-resource.azure.openai.com",
691),
692"https://deployments.example-resource.azure.openai.com/openai/",
693"/models",
694{},
695"https://deployments.example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
696),
697# AsyncAzureOpenAI: Deployment called "deployments"
698(
699AsyncAzureOpenAI(
700api_version="2024-02-01",
701api_key="example API key",
702azure_endpoint="https://example-resource.azure.openai.com",
703azure_deployment="deployments",
704),
705"https://example-resource.azure.openai.com/openai/deployments/deployments/",
706"/models",
707{},
708"https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01",
709),
710# AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported
711(
712AsyncAzureOpenAI( # type: ignore
713api_version="2024-02-01",
714api_key="example API key",
715base_url="https://example.azure-api.net/PTU/",
716azure_deployment="deployment-client",
717),
718"https://example.azure-api.net/PTU/",
719"/models",
720{},
721"https://example.azure-api.net/PTU/models?api-version=2024-02-01",
722),
723],
724)
725def test_prepare_url_nondeployment_endpoint(
726client: Client, base_url: str, api: str, json_data: dict[str, str], expected: str
727) -> None:
728req = client._build_request(
729FinalRequestOptions.construct(
730method="post",
731url=api,
732json_data=json_data,
733)
734)
735assert req.url == expected
736assert client.base_url == base_url
737
738
739@pytest.mark.parametrize(
740"client,base_url,json_data,expected",
741[
742# Realtime endpoint
743# AzureOpenAI: No deployment specified
744(
745AzureOpenAI(
746api_version="2024-02-01",
747api_key="example API key",
748azure_endpoint="https://example-resource.azure.openai.com",
749),
750"https://example-resource.azure.openai.com/openai/",
751{"model": "deployment-body"},
752"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body",
753),
754# AzureOpenAI: Deployment specified
755(
756AzureOpenAI(
757api_version="2024-02-01",
758api_key="example API key",
759azure_endpoint="https://example-resource.azure.openai.com",
760azure_deployment="deployment-client",
761),
762"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
763{"model": "deployment-body"},
764"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-client",
765),
766# AzureOpenAI: "deployments" in the DNS name
767(
768AzureOpenAI(
769api_version="2024-02-01",
770api_key="example API key",
771azure_endpoint="https://deployments.azure.openai.com",
772),
773"https://deployments.azure.openai.com/openai/",
774{"model": "deployment-body"},
775"wss://deployments.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body",
776),
777# AzureOpenAI: Deployment called "deployments"
778(
779AzureOpenAI(
780api_version="2024-02-01",
781api_key="example API key",
782azure_endpoint="https://example-resource.azure.openai.com",
783azure_deployment="deployments",
784),
785"https://example-resource.azure.openai.com/openai/deployments/deployments/",
786{"model": "deployment-body"},
787"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployments",
788),
789# AzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported
790(
791AzureOpenAI( # type: ignore
792api_version="2024-02-01",
793api_key="example API key",
794base_url="https://example.azure-api.net/PTU/",
795azure_deployment="my-deployment",
796),
797"https://example.azure-api.net/PTU/",
798{"model": "deployment-body"},
799"wss://example.azure-api.net/PTU/realtime?api-version=2024-02-01&deployment=deployment-body",
800),
801# AzureOpenAI: websocket_base_url specified
802(
803AzureOpenAI(
804api_version="2024-02-01",
805api_key="example API key",
806azure_endpoint="https://example-resource.azure.openai.com",
807websocket_base_url="wss://example-resource.azure.openai.com/base",
808),
809"https://example-resource.azure.openai.com/openai/",
810{"model": "deployment-body"},
811"wss://example-resource.azure.openai.com/base/realtime?api-version=2024-02-01&deployment=deployment-body",
812),
813],
814)
815def test_prepare_url_realtime(client: AzureOpenAI, base_url: str, json_data: dict[str, str], expected: str) -> None:
816url, _ = client._configure_realtime(json_data["model"], {})
817assert str(url) == expected
818assert client.base_url == base_url
819
820
821@pytest.mark.parametrize(
822"client,base_url,json_data,expected",
823[
824# AsyncAzureOpenAI: No deployment specified
825(
826AsyncAzureOpenAI(
827api_version="2024-02-01",
828api_key="example API key",
829azure_endpoint="https://example-resource.azure.openai.com",
830),
831"https://example-resource.azure.openai.com/openai/",
832{"model": "deployment-body"},
833"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body",
834),
835# AsyncAzureOpenAI: Deployment specified
836(
837AsyncAzureOpenAI(
838api_version="2024-02-01",
839api_key="example API key",
840azure_endpoint="https://example-resource.azure.openai.com",
841azure_deployment="deployment-client",
842),
843"https://example-resource.azure.openai.com/openai/deployments/deployment-client/",
844{"model": "deployment-body"},
845"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-client",
846),
847# AsyncAzureOpenAI: "deployments" in the DNS name
848(
849AsyncAzureOpenAI(
850api_version="2024-02-01",
851api_key="example API key",
852azure_endpoint="https://deployments.azure.openai.com",
853),
854"https://deployments.azure.openai.com/openai/",
855{"model": "deployment-body"},
856"wss://deployments.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployment-body",
857),
858# AsyncAzureOpenAI: Deployment called "deployments"
859(
860AsyncAzureOpenAI(
861api_version="2024-02-01",
862api_key="example API key",
863azure_endpoint="https://example-resource.azure.openai.com",
864azure_deployment="deployments",
865),
866"https://example-resource.azure.openai.com/openai/deployments/deployments/",
867{"model": "deployment-body"},
868"wss://example-resource.azure.openai.com/openai/realtime?api-version=2024-02-01&deployment=deployments",
869),
870# AsyncAzureOpenAI: base_url and azure_deployment specified; azure_deployment ignored b/c not supported
871(
872AsyncAzureOpenAI( # type: ignore
873api_version="2024-02-01",
874api_key="example API key",
875base_url="https://example.azure-api.net/PTU/",
876azure_deployment="deployment-client",
877),
878"https://example.azure-api.net/PTU/",
879{"model": "deployment-body"},
880"wss://example.azure-api.net/PTU/realtime?api-version=2024-02-01&deployment=deployment-body",
881),
882# AsyncAzureOpenAI: websocket_base_url specified
883(
884AsyncAzureOpenAI(
885api_version="2024-02-01",
886api_key="example API key",
887azure_endpoint="https://example-resource.azure.openai.com",
888websocket_base_url="wss://example-resource.azure.openai.com/base",
889),
890"https://example-resource.azure.openai.com/openai/",
891{"model": "deployment-body"},
892"wss://example-resource.azure.openai.com/base/realtime?api-version=2024-02-01&deployment=deployment-body",
893),
894],
895)
896async def test_prepare_url_realtime_async(
897client: AsyncAzureOpenAI, base_url: str, json_data: dict[str, str], expected: str
898) -> None:
899url, _ = await client._configure_realtime(json_data["model"], {})
900assert str(url) == expected
901assert client.base_url == base_url
902
903
904def test_client_sets_base_url(client: Client) -> None:
905client = AzureOpenAI(
906api_version="2024-02-01",
907api_key="example API key",
908azure_endpoint="https://example-resource.azure.openai.com",
909azure_deployment="my-deployment",
910)
911assert client.base_url == "https://example-resource.azure.openai.com/openai/deployments/my-deployment/"
912
913# (not recommended) user sets base_url to target different deployment
914client.base_url = "https://example-resource.azure.openai.com/openai/deployments/different-deployment/"
915req = client._build_request(
916FinalRequestOptions.construct(
917method="post",
918url="/chat/completions",
919json_data={"model": "placeholder"},
920)
921)
922assert (
923req.url
924== "https://example-resource.azure.openai.com/openai/deployments/different-deployment/chat/completions?api-version=2024-02-01"
925)
926req = client._build_request(
927FinalRequestOptions.construct(
928method="post",
929url="/models",
930json_data={},
931)
932)
933assert req.url == "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01"
934
935# (not recommended) user sets base_url to remove deployment
936client.base_url = "https://example-resource.azure.openai.com/openai/"
937req = client._build_request(
938FinalRequestOptions.construct(
939method="post",
940url="/chat/completions",
941json_data={"model": "deployment"},
942)
943)
944assert (
945req.url
946== "https://example-resource.azure.openai.com/openai/deployments/deployment/chat/completions?api-version=2024-02-01"
947)
948req = client._build_request(
949FinalRequestOptions.construct(
950method="post",
951url="/models",
952json_data={},
953)
954)
955assert req.url == "https://example-resource.azure.openai.com/openai/models?api-version=2024-02-01"