Skip to content

Commit e507a4e

Browse files
release: 2.32.0 (#3074)
1 parent 750354e commit e507a4e

36 files changed

+1888
-260
lines changed

.github/workflows/ci.yml

Lines changed: 20 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -23,13 +23,11 @@ jobs:
2323
steps:
2424
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
2525

26-
- name: Install Rye
27-
run: |
28-
curl -sSf https://rye.astral.sh/get | bash
29-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
30-
env:
31-
RYE_VERSION: '0.44.0'
32-
RYE_INSTALL_OPTION: '--yes'
26+
- name: Set up Rye
27+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
28+
with:
29+
version: '0.44.0'
30+
enable-cache: true
3331

3432
- name: Install dependencies
3533
run: rye sync --all-features
@@ -48,13 +46,11 @@ jobs:
4846
steps:
4947
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
5048

51-
- name: Install Rye
52-
run: |
53-
curl -sSf https://rye.astral.sh/get | bash
54-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
55-
env:
56-
RYE_VERSION: '0.44.0'
57-
RYE_INSTALL_OPTION: '--yes'
49+
- name: Set up Rye
50+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
51+
with:
52+
version: '0.44.0'
53+
enable-cache: true
5854

5955
- name: Install dependencies
6056
run: rye sync --all-features
@@ -89,13 +85,11 @@ jobs:
8985
steps:
9086
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
9187

92-
- name: Install Rye
93-
run: |
94-
curl -sSf https://rye.astral.sh/get | bash
95-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
96-
env:
97-
RYE_VERSION: '0.44.0'
98-
RYE_INSTALL_OPTION: '--yes'
88+
- name: Set up Rye
89+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
90+
with:
91+
version: '0.44.0'
92+
enable-cache: true
9993

10094
- name: Bootstrap
10195
run: ./scripts/bootstrap
@@ -112,13 +106,11 @@ jobs:
112106
steps:
113107
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
114108

115-
- name: Install Rye
116-
run: |
117-
curl -sSf https://rye.astral.sh/get | bash
118-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
119-
env:
120-
RYE_VERSION: '0.44.0'
121-
RYE_INSTALL_OPTION: '--yes'
109+
- name: Set up Rye
110+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
111+
with:
112+
version: '0.44.0'
113+
enable-cache: true
122114
- name: Install dependencies
123115
run: |
124116
rye sync --all-features

.github/workflows/create-releases.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,12 @@ jobs:
2222
repo: ${{ github.event.repository.full_name }}
2323
stainless-api-key: ${{ secrets.STAINLESS_API_KEY }}
2424

25-
- name: Install Rye
25+
- name: Set up Rye
2626
if: ${{ steps.release.outputs.releases_created }}
27-
run: |
28-
curl -sSf https://rye.astral.sh/get | bash
29-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
30-
env:
31-
RYE_VERSION: '0.44.0'
32-
RYE_INSTALL_OPTION: '--yes'
27+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
28+
with:
29+
version: '0.44.0'
30+
enable-cache: true
3331

3432
- name: Publish to PyPI
3533
if: ${{ steps.release.outputs.releases_created }}

.github/workflows/detect-breaking-changes.yml

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,11 @@ jobs:
2020
# Ensure we can check out the pull request base in the script below.
2121
fetch-depth: ${{ env.FETCH_DEPTH }}
2222

23-
- name: Install Rye
24-
run: |
25-
curl -sSf https://rye.astral.sh/get | bash
26-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
27-
env:
28-
RYE_VERSION: '0.44.0'
29-
RYE_INSTALL_OPTION: '--yes'
23+
- name: Set up Rye
24+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
25+
with:
26+
version: '0.44.0'
27+
enable-cache: true
3028
- name: Install dependencies
3129
run: |
3230
rye sync --all-features
@@ -49,14 +47,12 @@ jobs:
4947
with:
5048
path: openai-python
5149

52-
- name: Install Rye
53-
working-directory: openai-python
54-
run: |
55-
curl -sSf https://rye.astral.sh/get | bash
56-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
57-
env:
58-
RYE_VERSION: '0.44.0'
59-
RYE_INSTALL_OPTION: '--yes'
50+
- name: Set up Rye
51+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
52+
with:
53+
version: '0.44.0'
54+
enable-cache: true
55+
working-directory: openai-python
6056

6157
- name: Install dependencies
6258
working-directory: openai-python
@@ -85,4 +81,3 @@ jobs:
8581
- name: Run integration type checks
8682
working-directory: openai-agents-python
8783
run: make mypy
88-

.github/workflows/publish-pypi.yml

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@ jobs:
1313
steps:
1414
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
1515

16-
- name: Install Rye
17-
run: |
18-
curl -sSf https://rye.astral.sh/get | bash
19-
echo "$HOME/.rye/shims" >> $GITHUB_PATH
20-
env:
21-
RYE_VERSION: '0.44.0'
22-
RYE_INSTALL_OPTION: '--yes'
16+
- name: Set up Rye
17+
uses: eifinger/setup-rye@c694239a43768373e87d0103d7f547027a23f3c8
18+
with:
19+
version: '0.44.0'
20+
enable-cache: true
2321

2422
- name: Publish to PyPI
2523
run: |

.release-please-manifest.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
{
2-
".": "2.31.0"
2+
".": "2.32.0"
33
}

.stats.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11
configured_endpoints: 152
2-
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-a6eca1bd01e0c434af356fe5275c206057216a4e626d1051d294c27016cd6d05.yml
3-
openapi_spec_hash: 68abda9122013a9ae3f084cfdbe8e8c1
4-
config_hash: 4975e16a94e8f9901428022044131888
2+
openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/openai%2Fopenai-7c540cce6eb30401259f4831ea9803b6d88501605d13734f98212cbb3b199e10.yml
3+
openapi_spec_hash: 06e656be22bbb92689954253668b42fc
4+
config_hash: 1a88b104658b6c854117996c080ebe6b

CHANGELOG.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,27 @@
11
# Changelog
22

3+
## 2.32.0 (2026-04-15)
4+
5+
Full Changelog: [v2.31.0...v2.32.0](https://github.com/openai/openai-python/compare/v2.31.0...v2.32.0)
6+
7+
### Features
8+
9+
* **api:** Add detail to InputFileContent ([60de21d](https://github.com/openai/openai-python/commit/60de21d1fcfbcadea0d9b8d884c73c9dc49d14ff))
10+
* **api:** add OAuthErrorCode type ([0c8d2c3](https://github.com/openai/openai-python/commit/0c8d2c3b44242c9139dc554896ea489b56e236b8))
11+
* **client:** add event handler implementation for websockets ([0280d05](https://github.com/openai/openai-python/commit/0280d0568f706684ecbf0aabf3575cdcb7fd22d5))
12+
* **client:** allow enqueuing to websockets even when not connected ([67aa20e](https://github.com/openai/openai-python/commit/67aa20e69bc0e4a3b7694327c808606bfa24a966))
13+
* **client:** support reconnection in websockets ([eb72a95](https://github.com/openai/openai-python/commit/eb72a953ea9dc5beec3eef537be6eb32292c3f65))
14+
15+
16+
### Bug Fixes
17+
18+
* ensure file data are only sent as 1 parameter ([c0c2ecd](https://github.com/openai/openai-python/commit/c0c2ecd0f6b64fa5fafda6134bb06995b143a2cf))
19+
20+
21+
### Documentation
22+
23+
* improve examples ([84712fa](https://github.com/openai/openai-python/commit/84712fa0f094b53151a0fe6ac85aa98018b2a7e2))
24+
325
## 2.31.0 (2026-04-08)
426

527
Full Changelog: [v2.30.0...v2.31.0](https://github.com/openai/openai-python/compare/v2.30.0...v2.31.0)

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "openai"
3-
version = "2.31.0"
3+
version = "2.32.0"
44
description = "The official Python library for the openai API"
55
dynamic = ["readme"]
66
license = "Apache-2.0"

src/openai/__init__.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,14 +29,17 @@
2929
InternalServerError,
3030
PermissionDeniedError,
3131
LengthFinishReasonError,
32+
WebSocketQueueFullError,
3233
UnprocessableEntityError,
3334
APIResponseValidationError,
3435
InvalidWebhookSignatureError,
3536
ContentFilterFinishReasonError,
37+
WebSocketConnectionClosedError,
3638
)
3739
from ._base_client import DefaultHttpxClient, DefaultAioHttpClient, DefaultAsyncHttpxClient
3840
from ._utils._logs import setup_logging as _setup_logging
3941
from ._legacy_response import HttpxBinaryResponseContent as HttpxBinaryResponseContent
42+
from .types.websocket_reconnection import ReconnectingEvent, ReconnectingOverrides
4043

4144
__all__ = [
4245
"types",
@@ -84,6 +87,10 @@
8487
"DefaultHttpxClient",
8588
"DefaultAsyncHttpxClient",
8689
"DefaultAioHttpClient",
90+
"ReconnectingEvent",
91+
"ReconnectingOverrides",
92+
"WebSocketQueueFullError",
93+
"WebSocketConnectionClosedError",
8794
]
8895

8996
if not _t.TYPE_CHECKING:

src/openai/_event_handler.py

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# File generated from our OpenAPI spec by Stainless. See CONTRIBUTING.md for details.
2+
3+
from __future__ import annotations
4+
5+
import threading
6+
from typing import Any, Callable
7+
8+
EventHandler = Callable[..., Any]
9+
10+
11+
class EventHandlerRegistry:
12+
"""Thread-safe (optional) registry of event handlers."""
13+
14+
def __init__(self, *, use_lock: bool = False) -> None:
15+
self._handlers: dict[str, list[EventHandler]] = {}
16+
self._once_ids: set[int] = set()
17+
self._lock: threading.Lock | None = threading.Lock() if use_lock else None
18+
19+
def _acquire(self) -> None:
20+
if self._lock is not None:
21+
self._lock.acquire()
22+
23+
def _release(self) -> None:
24+
if self._lock is not None:
25+
self._lock.release()
26+
27+
def add(self, event_type: str, handler: EventHandler, *, once: bool = False) -> None:
28+
self._acquire()
29+
try:
30+
handlers = self._handlers.setdefault(event_type, [])
31+
handlers.append(handler)
32+
if once:
33+
self._once_ids.add(id(handler))
34+
finally:
35+
self._release()
36+
37+
def remove(self, event_type: str, handler: EventHandler) -> None:
38+
self._acquire()
39+
try:
40+
handlers = self._handlers.get(event_type)
41+
if handlers is not None:
42+
try:
43+
handlers.remove(handler)
44+
except ValueError:
45+
pass
46+
self._once_ids.discard(id(handler))
47+
finally:
48+
self._release()
49+
50+
def get_handlers(self, event_type: str) -> list[EventHandler]:
51+
"""Return a snapshot of handlers for the given event type, removing once-handlers."""
52+
self._acquire()
53+
try:
54+
handlers = self._handlers.get(event_type)
55+
if not handlers:
56+
return []
57+
result = list(handlers)
58+
to_remove = [h for h in result if id(h) in self._once_ids]
59+
for h in to_remove:
60+
handlers.remove(h)
61+
self._once_ids.discard(id(h))
62+
return result
63+
finally:
64+
self._release()
65+
66+
def has_handlers(self, event_type: str) -> bool:
67+
self._acquire()
68+
try:
69+
handlers = self._handlers.get(event_type)
70+
return bool(handlers)
71+
finally:
72+
self._release()
73+
74+
def merge_into(self, target: EventHandlerRegistry) -> None:
75+
"""Move all handlers from this registry into *target*, then clear self."""
76+
self._acquire()
77+
try:
78+
for event_type, handlers in self._handlers.items():
79+
for handler in handlers:
80+
once = id(handler) in self._once_ids
81+
target.add(event_type, handler, once=once)
82+
self._handlers.clear()
83+
self._once_ids.clear()
84+
finally:
85+
self._release()

0 commit comments

Comments
 (0)