Skip to content

Commit 0c489f1

Browse files
feat(client): add header OpenAI-Project (#1320)
1 parent 1a83130 commit 0c489f1

File tree

4 files changed

+48
-0
lines changed

4 files changed

+48
-0
lines changed

src/openai/__init__.py

+14
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,8 @@
108108

109109
organization: str | None = None
110110

111+
project: str | None = None
112+
111113
base_url: str | _httpx.URL | None = None
112114

113115
timeout: float | Timeout | None = DEFAULT_TIMEOUT
@@ -159,6 +161,17 @@ def organization(self, value: str | None) -> None: # type: ignore
159161

160162
organization = value
161163

164+
@property # type: ignore
165+
@override
166+
def project(self) -> str | None:
167+
return project
168+
169+
@project.setter # type: ignore
170+
def project(self, value: str | None) -> None: # type: ignore
171+
global project
172+
173+
project = value
174+
162175
@property
163176
@override
164177
def base_url(self) -> _httpx.URL:
@@ -310,6 +323,7 @@ def _load_client() -> OpenAI: # type: ignore[reportUnusedFunction]
310323
_client = _ModuleClient(
311324
api_key=api_key,
312325
organization=organization,
326+
project=project,
313327
base_url=base_url,
314328
timeout=timeout,
315329
max_retries=max_retries,

src/openai/_client.py

+20
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,14 @@ class OpenAI(SyncAPIClient):
6464
# client options
6565
api_key: str
6666
organization: str | None
67+
project: str | None
6768

6869
def __init__(
6970
self,
7071
*,
7172
api_key: str | None = None,
7273
organization: str | None = None,
74+
project: str | None = None,
7375
base_url: str | httpx.URL | None = None,
7476
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
7577
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -94,6 +96,7 @@ def __init__(
9496
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
9597
- `api_key` from `OPENAI_API_KEY`
9698
- `organization` from `OPENAI_ORG_ID`
99+
- `project` from `OPENAI_PROJECT_ID`
97100
"""
98101
if api_key is None:
99102
api_key = os.environ.get("OPENAI_API_KEY")
@@ -107,6 +110,10 @@ def __init__(
107110
organization = os.environ.get("OPENAI_ORG_ID")
108111
self.organization = organization
109112

113+
if project is None:
114+
project = os.environ.get("OPENAI_PROJECT_ID")
115+
self.project = project
116+
110117
if base_url is None:
111118
base_url = os.environ.get("OPENAI_BASE_URL")
112119
if base_url is None:
@@ -157,6 +164,7 @@ def default_headers(self) -> dict[str, str | Omit]:
157164
**super().default_headers,
158165
"X-Stainless-Async": "false",
159166
"OpenAI-Organization": self.organization if self.organization is not None else Omit(),
167+
"OpenAI-Project": self.project if self.project is not None else Omit(),
160168
**self._custom_headers,
161169
}
162170

@@ -165,6 +173,7 @@ def copy(
165173
*,
166174
api_key: str | None = None,
167175
organization: str | None = None,
176+
project: str | None = None,
168177
base_url: str | httpx.URL | None = None,
169178
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
170179
http_client: httpx.Client | None = None,
@@ -200,6 +209,7 @@ def copy(
200209
return self.__class__(
201210
api_key=api_key or self.api_key,
202211
organization=organization or self.organization,
212+
project=project or self.project,
203213
base_url=base_url or self.base_url,
204214
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
205215
http_client=http_client,
@@ -266,12 +276,14 @@ class AsyncOpenAI(AsyncAPIClient):
266276
# client options
267277
api_key: str
268278
organization: str | None
279+
project: str | None
269280

270281
def __init__(
271282
self,
272283
*,
273284
api_key: str | None = None,
274285
organization: str | None = None,
286+
project: str | None = None,
275287
base_url: str | httpx.URL | None = None,
276288
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
277289
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -296,6 +308,7 @@ def __init__(
296308
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
297309
- `api_key` from `OPENAI_API_KEY`
298310
- `organization` from `OPENAI_ORG_ID`
311+
- `project` from `OPENAI_PROJECT_ID`
299312
"""
300313
if api_key is None:
301314
api_key = os.environ.get("OPENAI_API_KEY")
@@ -309,6 +322,10 @@ def __init__(
309322
organization = os.environ.get("OPENAI_ORG_ID")
310323
self.organization = organization
311324

325+
if project is None:
326+
project = os.environ.get("OPENAI_PROJECT_ID")
327+
self.project = project
328+
312329
if base_url is None:
313330
base_url = os.environ.get("OPENAI_BASE_URL")
314331
if base_url is None:
@@ -359,6 +376,7 @@ def default_headers(self) -> dict[str, str | Omit]:
359376
**super().default_headers,
360377
"X-Stainless-Async": f"async:{get_async_library()}",
361378
"OpenAI-Organization": self.organization if self.organization is not None else Omit(),
379+
"OpenAI-Project": self.project if self.project is not None else Omit(),
362380
**self._custom_headers,
363381
}
364382

@@ -367,6 +385,7 @@ def copy(
367385
*,
368386
api_key: str | None = None,
369387
organization: str | None = None,
388+
project: str | None = None,
370389
base_url: str | httpx.URL | None = None,
371390
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
372391
http_client: httpx.AsyncClient | None = None,
@@ -402,6 +421,7 @@ def copy(
402421
return self.__class__(
403422
api_key=api_key or self.api_key,
404423
organization=organization or self.organization,
424+
project=project or self.project,
405425
base_url=base_url or self.base_url,
406426
timeout=self.timeout if isinstance(timeout, NotGiven) else timeout,
407427
http_client=http_client,

src/openai/lib/azure.py

+13
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ def __init__(
130130
azure_ad_token: str | None = None,
131131
azure_ad_token_provider: AzureADTokenProvider | None = None,
132132
organization: str | None = None,
133+
project: str | None = None,
133134
base_url: str | None = None,
134135
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
135136
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -143,6 +144,7 @@ def __init__(
143144
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
144145
- `api_key` from `AZURE_OPENAI_API_KEY`
145146
- `organization` from `OPENAI_ORG_ID`
147+
- `project` from `OPENAI_PROJECT_ID`
146148
- `azure_ad_token` from `AZURE_OPENAI_AD_TOKEN`
147149
- `api_version` from `OPENAI_API_VERSION`
148150
- `azure_endpoint` from `AZURE_OPENAI_ENDPOINT`
@@ -205,6 +207,7 @@ def __init__(
205207
super().__init__(
206208
api_key=api_key,
207209
organization=organization,
210+
project=project,
208211
base_url=base_url,
209212
timeout=timeout,
210213
max_retries=max_retries,
@@ -223,6 +226,7 @@ def copy(
223226
*,
224227
api_key: str | None = None,
225228
organization: str | None = None,
229+
project: str | None = None,
226230
api_version: str | None = None,
227231
azure_ad_token: str | None = None,
228232
azure_ad_token_provider: AzureADTokenProvider | None = None,
@@ -242,6 +246,7 @@ def copy(
242246
return super().copy(
243247
api_key=api_key,
244248
organization=organization,
249+
project=project,
245250
base_url=base_url,
246251
timeout=timeout,
247252
http_client=http_client,
@@ -306,6 +311,7 @@ def __init__(
306311
azure_ad_token: str | None = None,
307312
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
308313
organization: str | None = None,
314+
project: str | None = None,
309315
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
310316
max_retries: int = DEFAULT_MAX_RETRIES,
311317
default_headers: Mapping[str, str] | None = None,
@@ -325,6 +331,7 @@ def __init__(
325331
azure_ad_token: str | None = None,
326332
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
327333
organization: str | None = None,
334+
project: str | None = None,
328335
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
329336
max_retries: int = DEFAULT_MAX_RETRIES,
330337
default_headers: Mapping[str, str] | None = None,
@@ -344,6 +351,7 @@ def __init__(
344351
azure_ad_token: str | None = None,
345352
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
346353
organization: str | None = None,
354+
project: str | None = None,
347355
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
348356
max_retries: int = DEFAULT_MAX_RETRIES,
349357
default_headers: Mapping[str, str] | None = None,
@@ -363,6 +371,7 @@ def __init__(
363371
azure_ad_token: str | None = None,
364372
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
365373
organization: str | None = None,
374+
project: str | None = None,
366375
base_url: str | None = None,
367376
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
368377
max_retries: int = DEFAULT_MAX_RETRIES,
@@ -376,6 +385,7 @@ def __init__(
376385
This automatically infers the following arguments from their corresponding environment variables if they are not provided:
377386
- `api_key` from `AZURE_OPENAI_API_KEY`
378387
- `organization` from `OPENAI_ORG_ID`
388+
- `project` from `OPENAI_PROJECT_ID`
379389
- `azure_ad_token` from `AZURE_OPENAI_AD_TOKEN`
380390
- `api_version` from `OPENAI_API_VERSION`
381391
- `azure_endpoint` from `AZURE_OPENAI_ENDPOINT`
@@ -438,6 +448,7 @@ def __init__(
438448
super().__init__(
439449
api_key=api_key,
440450
organization=organization,
451+
project=project,
441452
base_url=base_url,
442453
timeout=timeout,
443454
max_retries=max_retries,
@@ -456,6 +467,7 @@ def copy(
456467
*,
457468
api_key: str | None = None,
458469
organization: str | None = None,
470+
project: str | None = None,
459471
api_version: str | None = None,
460472
azure_ad_token: str | None = None,
461473
azure_ad_token_provider: AsyncAzureADTokenProvider | None = None,
@@ -475,6 +487,7 @@ def copy(
475487
return super().copy(
476488
api_key=api_key,
477489
organization=organization,
490+
project=project,
478491
base_url=base_url,
479492
timeout=timeout,
480493
http_client=http_client,

tests/test_module_client.py

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ def reset_state() -> None:
1616
openai._reset_client()
1717
openai.api_key = None or "My API Key"
1818
openai.organization = None
19+
openai.project = None
1920
openai.base_url = None
2021
openai.timeout = DEFAULT_TIMEOUT
2122
openai.max_retries = DEFAULT_MAX_RETRIES

0 commit comments

Comments
 (0)