Skip to content

Commit acc190a

Browse files
chore(types): change optional parameter type from NotGiven to Omit
1 parent 0d85ca0 commit acc190a

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

56 files changed

+2723
-2730
lines changed

src/openai/__init__.py

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
from typing_extensions import override
88

99
from . import types
10-
from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes
10+
from ._types import NOT_GIVEN, Omit, NoneType, NotGiven, Transport, ProxiesTypes, omit, not_given
1111
from ._utils import file_from_path
1212
from ._client import Client, OpenAI, Stream, Timeout, Transport, AsyncClient, AsyncOpenAI, AsyncStream, RequestOptions
1313
from ._models import BaseModel
@@ -46,7 +46,9 @@
4646
"ProxiesTypes",
4747
"NotGiven",
4848
"NOT_GIVEN",
49+
"not_given",
4950
"Omit",
51+
"omit",
5052
"OpenAIError",
5153
"APIError",
5254
"APIStatusError",

src/openai/_base_client.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242
from ._qs import Querystring
4343
from ._files import to_httpx_files, async_to_httpx_files
4444
from ._types import (
45-
NOT_GIVEN,
4645
Body,
4746
Omit,
4847
Query,
@@ -57,6 +56,7 @@
5756
RequestOptions,
5857
HttpxRequestFiles,
5958
ModelBuilderProtocol,
59+
not_given,
6060
)
6161
from ._utils import SensitiveHeadersFilter, is_dict, is_list, asyncify, is_given, lru_cache, is_mapping
6262
from ._compat import PYDANTIC_V1, model_copy, model_dump
@@ -147,9 +147,9 @@ def __init__(
147147
def __init__(
148148
self,
149149
*,
150-
url: URL | NotGiven = NOT_GIVEN,
151-
json: Body | NotGiven = NOT_GIVEN,
152-
params: Query | NotGiven = NOT_GIVEN,
150+
url: URL | NotGiven = not_given,
151+
json: Body | NotGiven = not_given,
152+
params: Query | NotGiven = not_given,
153153
) -> None:
154154
self.url = url
155155
self.json = json
@@ -597,7 +597,7 @@ def _maybe_override_cast_to(self, cast_to: type[ResponseT], options: FinalReques
597597
# we internally support defining a temporary header to override the
598598
# default `cast_to` type for use with `.with_raw_response` and `.with_streaming_response`
599599
# see _response.py for implementation details
600-
override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, NOT_GIVEN)
600+
override_cast_to = headers.pop(OVERRIDE_CAST_TO_HEADER, not_given)
601601
if is_given(override_cast_to):
602602
options.headers = headers
603603
return cast(Type[ResponseT], override_cast_to)
@@ -827,7 +827,7 @@ def __init__(
827827
version: str,
828828
base_url: str | URL,
829829
max_retries: int = DEFAULT_MAX_RETRIES,
830-
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
830+
timeout: float | Timeout | None | NotGiven = not_given,
831831
http_client: httpx.Client | None = None,
832832
custom_headers: Mapping[str, str] | None = None,
833833
custom_query: Mapping[str, object] | None = None,
@@ -1373,7 +1373,7 @@ def __init__(
13731373
base_url: str | URL,
13741374
_strict_response_validation: bool,
13751375
max_retries: int = DEFAULT_MAX_RETRIES,
1376-
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
1376+
timeout: float | Timeout | None | NotGiven = not_given,
13771377
http_client: httpx.AsyncClient | None = None,
13781378
custom_headers: Mapping[str, str] | None = None,
13791379
custom_query: Mapping[str, object] | None = None,
@@ -1850,8 +1850,8 @@ def make_request_options(
18501850
extra_query: Query | None = None,
18511851
extra_body: Body | None = None,
18521852
idempotency_key: str | None = None,
1853-
timeout: float | httpx.Timeout | None | NotGiven = NOT_GIVEN,
1854-
post_parser: PostParser | NotGiven = NOT_GIVEN,
1853+
timeout: float | httpx.Timeout | None | NotGiven = not_given,
1854+
post_parser: PostParser | NotGiven = not_given,
18551855
) -> RequestOptions:
18561856
"""Create a dict of type RequestOptions without keys of NotGiven values."""
18571857
options: RequestOptions = {}

src/openai/_client.py

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,21 @@
33
from __future__ import annotations
44

55
import os
6-
from typing import TYPE_CHECKING, Any, Union, Mapping, Callable, Awaitable
6+
from typing import TYPE_CHECKING, Any, Mapping, Callable, Awaitable
77
from typing_extensions import Self, override
88

99
import httpx
1010

1111
from . import _exceptions
1212
from ._qs import Querystring
1313
from ._types import (
14-
NOT_GIVEN,
1514
Omit,
1615
Timeout,
1716
NotGiven,
1817
Transport,
1918
ProxiesTypes,
2019
RequestOptions,
20+
not_given,
2121
)
2222
from ._utils import (
2323
is_given,
@@ -103,7 +103,7 @@ def __init__(
103103
webhook_secret: str | None = None,
104104
base_url: str | httpx.URL | None = None,
105105
websocket_base_url: str | httpx.URL | None = None,
106-
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
106+
timeout: float | Timeout | None | NotGiven = not_given,
107107
max_retries: int = DEFAULT_MAX_RETRIES,
108108
default_headers: Mapping[str, str] | None = None,
109109
default_query: Mapping[str, object] | None = None,
@@ -339,9 +339,9 @@ def copy(
339339
webhook_secret: str | None = None,
340340
websocket_base_url: str | httpx.URL | None = None,
341341
base_url: str | httpx.URL | None = None,
342-
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
342+
timeout: float | Timeout | None | NotGiven = not_given,
343343
http_client: httpx.Client | None = None,
344-
max_retries: int | NotGiven = NOT_GIVEN,
344+
max_retries: int | NotGiven = not_given,
345345
default_headers: Mapping[str, str] | None = None,
346346
set_default_headers: Mapping[str, str] | None = None,
347347
default_query: Mapping[str, object] | None = None,
@@ -448,7 +448,7 @@ def __init__(
448448
webhook_secret: str | None = None,
449449
base_url: str | httpx.URL | None = None,
450450
websocket_base_url: str | httpx.URL | None = None,
451-
timeout: Union[float, Timeout, None, NotGiven] = NOT_GIVEN,
451+
timeout: float | Timeout | None | NotGiven = not_given,
452452
max_retries: int = DEFAULT_MAX_RETRIES,
453453
default_headers: Mapping[str, str] | None = None,
454454
default_query: Mapping[str, object] | None = None,
@@ -684,9 +684,9 @@ def copy(
684684
webhook_secret: str | None = None,
685685
websocket_base_url: str | httpx.URL | None = None,
686686
base_url: str | httpx.URL | None = None,
687-
timeout: float | Timeout | None | NotGiven = NOT_GIVEN,
687+
timeout: float | Timeout | None | NotGiven = not_given,
688688
http_client: httpx.AsyncClient | None = None,
689-
max_retries: int | NotGiven = NOT_GIVEN,
689+
max_retries: int | NotGiven = not_given,
690690
default_headers: Mapping[str, str] | None = None,
691691
set_default_headers: Mapping[str, str] | None = None,
692692
default_query: Mapping[str, object] | None = None,

src/openai/_qs.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from urllib.parse import parse_qs, urlencode
55
from typing_extensions import Literal, get_args
66

7-
from ._types import NOT_GIVEN, NotGiven, NotGivenOr
7+
from ._types import NotGiven, not_given
88
from ._utils import flatten
99

1010
_T = TypeVar("_T")
@@ -41,8 +41,8 @@ def stringify(
4141
self,
4242
params: Params,
4343
*,
44-
array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
45-
nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
44+
array_format: ArrayFormat | NotGiven = not_given,
45+
nested_format: NestedFormat | NotGiven = not_given,
4646
) -> str:
4747
return urlencode(
4848
self.stringify_items(
@@ -56,8 +56,8 @@ def stringify_items(
5656
self,
5757
params: Params,
5858
*,
59-
array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
60-
nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
59+
array_format: ArrayFormat | NotGiven = not_given,
60+
nested_format: NestedFormat | NotGiven = not_given,
6161
) -> list[tuple[str, str]]:
6262
opts = Options(
6363
qs=self,
@@ -143,8 +143,8 @@ def __init__(
143143
self,
144144
qs: Querystring = _qs,
145145
*,
146-
array_format: NotGivenOr[ArrayFormat] = NOT_GIVEN,
147-
nested_format: NotGivenOr[NestedFormat] = NOT_GIVEN,
146+
array_format: ArrayFormat | NotGiven = not_given,
147+
nested_format: NestedFormat | NotGiven = not_given,
148148
) -> None:
149149
self.array_format = qs.array_format if isinstance(array_format, NotGiven) else array_format
150150
self.nested_format = qs.nested_format if isinstance(nested_format, NotGiven) else nested_format

src/openai/_types.py

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -118,18 +118,21 @@ class RequestOptions(TypedDict, total=False):
118118
# Sentinel class used until PEP 0661 is accepted
119119
class NotGiven:
120120
"""
121-
A sentinel singleton class used to distinguish omitted keyword arguments
122-
from those passed in with the value None (which may have different behavior).
121+
For parameters with a meaningful None value, we need to distinguish between
122+
the user explicitly passing None, and the user not passing the parameter at
123+
all.
124+
125+
User code shouldn't need to use not_given directly.
123126
124127
For example:
125128
126129
```py
127-
def get(timeout: Union[int, NotGiven, None] = NotGiven()) -> Response: ...
130+
def create(timeout: Timeout | None | NotGiven = not_given): ...
128131
129132
130-
get(timeout=1) # 1s timeout
131-
get(timeout=None) # No timeout
132-
get() # Default timeout behavior, which may not be statically known at the method definition.
133+
create(timeout=1) # 1s timeout
134+
create(timeout=None) # No timeout
135+
create() # Default timeout behavior
133136
```
134137
"""
135138

@@ -141,13 +144,14 @@ def __repr__(self) -> str:
141144
return "NOT_GIVEN"
142145

143146

144-
NotGivenOr = Union[_T, NotGiven]
147+
not_given = NotGiven()
148+
# for backwards compatibility:
145149
NOT_GIVEN = NotGiven()
146150

147151

148152
class Omit:
149-
"""In certain situations you need to be able to represent a case where a default value has
150-
to be explicitly removed and `None` is not an appropriate substitute, for example:
153+
"""
154+
To explicitly omit something from being sent in a request, use `omit`.
151155
152156
```py
153157
# as the default `Content-Type` header is `application/json` that will be sent
@@ -157,15 +161,20 @@ class Omit:
157161
# to look something like: 'multipart/form-data; boundary=0d8382fcf5f8c3be01ca2e11002d2983'
158162
client.post(..., headers={"Content-Type": "multipart/form-data"})
159163
160-
# instead you can remove the default `application/json` header by passing Omit
161-
client.post(..., headers={"Content-Type": Omit()})
164+
# instead you can remove the default `application/json` header by passing omit
165+
client.post(..., headers={"Content-Type": omit})
162166
```
163167
"""
164168

165169
def __bool__(self) -> Literal[False]:
166170
return False
167171

168172

173+
omit = Omit()
174+
175+
Omittable = Union[_T, Omit]
176+
177+
169178
@runtime_checkable
170179
class ModelBuilderProtocol(Protocol):
171180
@classmethod

src/openai/_utils/_transform.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ def _transform_typeddict(
268268
annotations = get_type_hints(expected_type, include_extras=True)
269269
for key, value in data.items():
270270
if not is_given(value):
271-
# we don't need to include `NotGiven` values here as they'll
271+
# we don't need to include omitted values here as they'll
272272
# be stripped out before the request is sent anyway
273273
continue
274274

@@ -434,7 +434,7 @@ async def _async_transform_typeddict(
434434
annotations = get_type_hints(expected_type, include_extras=True)
435435
for key, value in data.items():
436436
if not is_given(value):
437-
# we don't need to include `NotGiven` values here as they'll
437+
# we don't need to include omitted values here as they'll
438438
# be stripped out before the request is sent anyway
439439
continue
440440

src/openai/_utils/_utils.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@
2222

2323
import sniffio
2424

25-
from .._types import NotGiven, FileTypes, NotGivenOr, HeadersLike
25+
from .._types import Omit, NotGiven, FileTypes, HeadersLike
2626

2727
_T = TypeVar("_T")
2828
_TupleT = TypeVar("_TupleT", bound=Tuple[object, ...])
@@ -67,7 +67,7 @@ def _extract_items(
6767
try:
6868
key = path[index]
6969
except IndexError:
70-
if isinstance(obj, NotGiven):
70+
if not is_given(obj):
7171
# no value was provided - we can safely ignore
7272
return []
7373

@@ -130,8 +130,8 @@ def _extract_items(
130130
return []
131131

132132

133-
def is_given(obj: NotGivenOr[_T]) -> TypeGuard[_T]:
134-
return not isinstance(obj, NotGiven)
133+
def is_given(obj: _T | NotGiven | Omit) -> TypeGuard[_T]:
134+
return not isinstance(obj, NotGiven) and not isinstance(obj, Omit)
135135

136136

137137
# Type safe methods for narrowing types with TypeVars.

src/openai/cli/_api/audio.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
from argparse import ArgumentParser
66

77
from .._utils import get_client, print_model
8-
from ..._types import NOT_GIVEN
8+
from ..._types import omit
99
from .._models import BaseModel
1010
from .._progress import BufferReader
1111
from ...types.audio import Transcription
@@ -72,9 +72,9 @@ def transcribe(args: CLITranscribeArgs) -> None:
7272
get_client().audio.transcriptions.create(
7373
file=(args.file, buffer_reader),
7474
model=args.model,
75-
language=args.language or NOT_GIVEN,
76-
temperature=args.temperature or NOT_GIVEN,
77-
prompt=args.prompt or NOT_GIVEN,
75+
language=args.language or omit,
76+
temperature=args.temperature or omit,
77+
prompt=args.prompt or omit,
7878
# casts required because the API is typed for enums
7979
# but we don't want to validate that here for forwards-compat
8080
response_format=cast(Any, args.response_format),
@@ -95,8 +95,8 @@ def translate(args: CLITranslationArgs) -> None:
9595
get_client().audio.translations.create(
9696
file=(args.file, buffer_reader),
9797
model=args.model,
98-
temperature=args.temperature or NOT_GIVEN,
99-
prompt=args.prompt or NOT_GIVEN,
98+
temperature=args.temperature or omit,
99+
prompt=args.prompt or omit,
100100
# casts required because the API is typed for enums
101101
# but we don't want to validate that here for forwards-compat
102102
response_format=cast(Any, args.response_format),

src/openai/cli/_api/completions.py

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
from openai.types.completion import Completion
99

1010
from .._utils import get_client
11-
from ..._types import NOT_GIVEN, NotGivenOr
11+
from ..._types import Omittable, omit
1212
from ..._utils import is_given
1313
from .._errors import CLIError
1414
from .._models import BaseModel
@@ -95,18 +95,18 @@ class CLICompletionCreateArgs(BaseModel):
9595
stream: bool = False
9696

9797
prompt: Optional[str] = None
98-
n: NotGivenOr[int] = NOT_GIVEN
99-
stop: NotGivenOr[str] = NOT_GIVEN
100-
user: NotGivenOr[str] = NOT_GIVEN
101-
echo: NotGivenOr[bool] = NOT_GIVEN
102-
suffix: NotGivenOr[str] = NOT_GIVEN
103-
best_of: NotGivenOr[int] = NOT_GIVEN
104-
top_p: NotGivenOr[float] = NOT_GIVEN
105-
logprobs: NotGivenOr[int] = NOT_GIVEN
106-
max_tokens: NotGivenOr[int] = NOT_GIVEN
107-
temperature: NotGivenOr[float] = NOT_GIVEN
108-
presence_penalty: NotGivenOr[float] = NOT_GIVEN
109-
frequency_penalty: NotGivenOr[float] = NOT_GIVEN
98+
n: Omittable[int] = omit
99+
stop: Omittable[str] = omit
100+
user: Omittable[str] = omit
101+
echo: Omittable[bool] = omit
102+
suffix: Omittable[str] = omit
103+
best_of: Omittable[int] = omit
104+
top_p: Omittable[float] = omit
105+
logprobs: Omittable[int] = omit
106+
max_tokens: Omittable[int] = omit
107+
temperature: Omittable[float] = omit
108+
presence_penalty: Omittable[float] = omit
109+
frequency_penalty: Omittable[float] = omit
110110

111111

112112
class CLICompletions:

0 commit comments

Comments
 (0)