From eb909d30c6c4f6f4508a708bd8ca61c70a13cee7 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 21 Aug 2026 03:54:21 +0000 Subject: [PATCH 1/3] test(api): move fine-tuning positional tests out of generated code (#3706) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] I understand that this repository is auto-generated and my pull request may not be merged ## Changes being requested Keep the fine-tuning positional-argument regression coverage in handwritten tests, then restore the two generated test files to the recorded public generated snapshot. The generated examples use `fine_tuning_job_id=` and their original fake `after` values; the original positional calls remain tested. Only three test files change. Runtime code, dependencies, the API reference, compiler inputs, and generation metadata are unchanged. ## Additional context & links All 20 original methods and their client parameterizations are retained verbatim in [`tests/lib/test_fine_tuning_positional_arguments.py`](https://github.com/openai/openai-python/blob/4dd138db112ee8d02c6803e0f0b812c5c9be3dee/tests/lib/test_fine_tuning_positional_arguments.py): - [`TestCheckpoints`](https://github.com/openai/openai-python/blob/4dd138db112ee8d02c6803e0f0b812c5c9be3dee/tests/lib/test_fine_tuning_positional_arguments.py#L14) and [`TestAsyncCheckpoints`](https://github.com/openai/openai-python/blob/4dd138db112ee8d02c6803e0f0b812c5c9be3dee/tests/lib/test_fine_tuning_positional_arguments.py#L65) preserve `test_method_list`, `test_method_list_with_all_params`, `test_raw_response_list`, `test_streaming_response_list`, and `test_path_params_list`. - [`TestJobs`](https://github.com/openai/openai-python/blob/4dd138db112ee8d02c6803e0f0b812c5c9be3dee/tests/lib/test_fine_tuning_positional_arguments.py#L118) and [`TestAsyncJobs`](https://github.com/openai/openai-python/blob/4dd138db112ee8d02c6803e0f0b812c5c9be3dee/tests/lib/test_fine_tuning_positional_arguments.py#L169) preserve `test_method_list_events`, `test_method_list_events_with_all_params`, `test_raw_response_list_events`, `test_streaming_response_list_events`, and `test_path_params_list_events`. These retain the basic/all-parameter calls, parsed response types, raw/streaming response headers and close behavior, and empty-ID errors. The original loose, strict, and async aiohttp modes remain: **50 positional-call cases**, alongside the restored generated keyword-call examples. Validation: - Exact-source/AST proof for every retained method and parameterization; both generated files match the public snapshot byte-for-byte. - Pytest collection preserves all 50 original class/function/client-mode IDs after normalizing only the destination path, under both Pydantic versions. - `python -m pytest -n 0 tests/lib/test_fine_tuning_positional_arguments.py tests/api_resources/fine_tuning/jobs/test_checkpoints.py tests/api_resources/fine_tuning/test_jobs.py`: **220 passed under Pydantic v2 and 220 under v1**, against the checked-in API mock. - `./scripts/format` and `./scripts/lint` pass, including Ruff, Pyright, mypy, and import checks. Unrelated reporter-only formatting changes are excluded. - Verified public custom-code report: **40 → 38 mixed files**, exactly these two generated test customizations removed, and all other customizations unchanged. --- .../fine_tuning/jobs/test_checkpoints.py | 24 +- tests/api_resources/fine_tuning/test_jobs.py | 28 +-- .../test_fine_tuning_positional_arguments.py | 219 ++++++++++++++++++ 3 files changed, 245 insertions(+), 26 deletions(-) create mode 100644 tests/lib/test_fine_tuning_positional_arguments.py diff --git a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py index 64bfa9e731..da86179898 100644 --- a/tests/api_resources/fine_tuning/jobs/test_checkpoints.py +++ b/tests/api_resources/fine_tuning/jobs/test_checkpoints.py @@ -21,15 +21,15 @@ class TestCheckpoints: @parametrize def test_method_list(self, client: OpenAI) -> None: checkpoint = client.fine_tuning.jobs.checkpoints.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: checkpoint = client.fine_tuning.jobs.checkpoints.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - after="string", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", limit=0, ) assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) @@ -37,7 +37,7 @@ def test_method_list_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_list(self, client: OpenAI) -> None: response = client.fine_tuning.jobs.checkpoints.with_raw_response.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True @@ -48,7 +48,7 @@ def test_raw_response_list(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list(self, client: OpenAI) -> None: with client.fine_tuning.jobs.checkpoints.with_streaming_response.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -62,7 +62,7 @@ def test_streaming_response_list(self, client: OpenAI) -> None: def test_path_params_list(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): client.fine_tuning.jobs.checkpoints.with_raw_response.list( - "", + fine_tuning_job_id="", ) @@ -74,15 +74,15 @@ class TestAsyncCheckpoints: @parametrize async def test_method_list(self, async_client: AsyncOpenAI) -> None: checkpoint = await async_client.fine_tuning.jobs.checkpoints.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: checkpoint = await async_client.fine_tuning.jobs.checkpoints.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - after="string", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", limit=0, ) assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) @@ -90,7 +90,7 @@ async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> N @parametrize async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: response = await async_client.fine_tuning.jobs.checkpoints.with_raw_response.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True @@ -101,7 +101,7 @@ async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: async with async_client.fine_tuning.jobs.checkpoints.with_streaming_response.list( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -115,5 +115,5 @@ async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): await async_client.fine_tuning.jobs.checkpoints.with_raw_response.list( - "", + fine_tuning_job_id="", ) diff --git a/tests/api_resources/fine_tuning/test_jobs.py b/tests/api_resources/fine_tuning/test_jobs.py index 2168e3dc94..f95845f2a7 100644 --- a/tests/api_resources/fine_tuning/test_jobs.py +++ b/tests/api_resources/fine_tuning/test_jobs.py @@ -165,7 +165,7 @@ def test_method_list(self, client: OpenAI) -> None: @parametrize def test_method_list_with_all_params(self, client: OpenAI) -> None: job = client.fine_tuning.jobs.list( - after="string", + after="after", limit=0, metadata={"foo": "string"}, ) @@ -232,15 +232,15 @@ def test_path_params_cancel(self, client: OpenAI) -> None: @parametrize def test_method_list_events(self, client: OpenAI) -> None: job = client.fine_tuning.jobs.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) @parametrize def test_method_list_events_with_all_params(self, client: OpenAI) -> None: job = client.fine_tuning.jobs.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - after="string", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", limit=0, ) assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) @@ -248,7 +248,7 @@ def test_method_list_events_with_all_params(self, client: OpenAI) -> None: @parametrize def test_raw_response_list_events(self, client: OpenAI) -> None: response = client.fine_tuning.jobs.with_raw_response.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True @@ -259,7 +259,7 @@ def test_raw_response_list_events(self, client: OpenAI) -> None: @parametrize def test_streaming_response_list_events(self, client: OpenAI) -> None: with client.fine_tuning.jobs.with_streaming_response.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -273,7 +273,7 @@ def test_streaming_response_list_events(self, client: OpenAI) -> None: def test_path_params_list_events(self, client: OpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): client.fine_tuning.jobs.with_raw_response.list_events( - "", + fine_tuning_job_id="", ) @parametrize @@ -502,7 +502,7 @@ async def test_method_list(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: job = await async_client.fine_tuning.jobs.list( - after="string", + after="after", limit=0, metadata={"foo": "string"}, ) @@ -569,15 +569,15 @@ async def test_path_params_cancel(self, async_client: AsyncOpenAI) -> None: @parametrize async def test_method_list_events(self, async_client: AsyncOpenAI) -> None: job = await async_client.fine_tuning.jobs.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) @parametrize async def test_method_list_events_with_all_params(self, async_client: AsyncOpenAI) -> None: job = await async_client.fine_tuning.jobs.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", - after="string", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="after", limit=0, ) assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) @@ -585,7 +585,7 @@ async def test_method_list_events_with_all_params(self, async_client: AsyncOpenA @parametrize async def test_raw_response_list_events(self, async_client: AsyncOpenAI) -> None: response = await async_client.fine_tuning.jobs.with_raw_response.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) assert response.is_closed is True @@ -596,7 +596,7 @@ async def test_raw_response_list_events(self, async_client: AsyncOpenAI) -> None @parametrize async def test_streaming_response_list_events(self, async_client: AsyncOpenAI) -> None: async with async_client.fine_tuning.jobs.with_streaming_response.list_events( - "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + fine_tuning_job_id="ft-AF1WoRqd3aJAHsqc9NY7iL8F", ) as response: assert not response.is_closed assert response.http_request.headers.get("X-Stainless-Lang") == "python" @@ -610,7 +610,7 @@ async def test_streaming_response_list_events(self, async_client: AsyncOpenAI) - async def test_path_params_list_events(self, async_client: AsyncOpenAI) -> None: with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): await async_client.fine_tuning.jobs.with_raw_response.list_events( - "", + fine_tuning_job_id="", ) @parametrize diff --git a/tests/lib/test_fine_tuning_positional_arguments.py b/tests/lib/test_fine_tuning_positional_arguments.py new file mode 100644 index 0000000000..510ea2b674 --- /dev/null +++ b/tests/lib/test_fine_tuning_positional_arguments.py @@ -0,0 +1,219 @@ +from __future__ import annotations + +from typing import Any, cast + +import pytest + +from openai import OpenAI, AsyncOpenAI +from tests.utils import assert_matches_type +from openai.pagination import SyncCursorPage, AsyncCursorPage +from openai.types.fine_tuning import FineTuningJobEvent +from openai.types.fine_tuning.jobs import FineTuningJobCheckpoint + + +class TestCheckpoints: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list(self, client: OpenAI) -> None: + checkpoint = client.fine_tuning.jobs.checkpoints.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + def test_method_list_with_all_params(self, client: OpenAI) -> None: + checkpoint = client.fine_tuning.jobs.checkpoints.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="string", + limit=0, + ) + assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + def test_raw_response_list(self, client: OpenAI) -> None: + response = client.fine_tuning.jobs.checkpoints.with_raw_response.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + checkpoint = response.parse() + assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + def test_streaming_response_list(self, client: OpenAI) -> None: + with client.fine_tuning.jobs.checkpoints.with_streaming_response.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + checkpoint = response.parse() + assert_matches_type(SyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + client.fine_tuning.jobs.checkpoints.with_raw_response.list( + "", + ) + + +class TestAsyncCheckpoints: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list(self, async_client: AsyncOpenAI) -> None: + checkpoint = await async_client.fine_tuning.jobs.checkpoints.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + async def test_method_list_with_all_params(self, async_client: AsyncOpenAI) -> None: + checkpoint = await async_client.fine_tuning.jobs.checkpoints.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="string", + limit=0, + ) + assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + async def test_raw_response_list(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.jobs.checkpoints.with_raw_response.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + checkpoint = response.parse() + assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + @parametrize + async def test_streaming_response_list(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.jobs.checkpoints.with_streaming_response.list( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + checkpoint = await response.parse() + assert_matches_type(AsyncCursorPage[FineTuningJobCheckpoint], checkpoint, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + await async_client.fine_tuning.jobs.checkpoints.with_raw_response.list( + "", + ) + + +class TestJobs: + parametrize = pytest.mark.parametrize("client", [False, True], indirect=True, ids=["loose", "strict"]) + + @parametrize + def test_method_list_events(self, client: OpenAI) -> None: + job = client.fine_tuning.jobs.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + def test_method_list_events_with_all_params(self, client: OpenAI) -> None: + job = client.fine_tuning.jobs.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="string", + limit=0, + ) + assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + def test_raw_response_list_events(self, client: OpenAI) -> None: + response = client.fine_tuning.jobs.with_raw_response.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + def test_streaming_response_list_events(self, client: OpenAI) -> None: + with client.fine_tuning.jobs.with_streaming_response.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = response.parse() + assert_matches_type(SyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + def test_path_params_list_events(self, client: OpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + client.fine_tuning.jobs.with_raw_response.list_events( + "", + ) + + +class TestAsyncJobs: + parametrize = pytest.mark.parametrize( + "async_client", [False, True, {"http_client": "aiohttp"}], indirect=True, ids=["loose", "strict", "aiohttp"] + ) + + @parametrize + async def test_method_list_events(self, async_client: AsyncOpenAI) -> None: + job = await async_client.fine_tuning.jobs.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + async def test_method_list_events_with_all_params(self, async_client: AsyncOpenAI) -> None: + job = await async_client.fine_tuning.jobs.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + after="string", + limit=0, + ) + assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + async def test_raw_response_list_events(self, async_client: AsyncOpenAI) -> None: + response = await async_client.fine_tuning.jobs.with_raw_response.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) + + assert response.is_closed is True + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + job = response.parse() + assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + @parametrize + async def test_streaming_response_list_events(self, async_client: AsyncOpenAI) -> None: + async with async_client.fine_tuning.jobs.with_streaming_response.list_events( + "ft-AF1WoRqd3aJAHsqc9NY7iL8F", + ) as response: + assert not response.is_closed + assert response.http_request.headers.get("X-Stainless-Lang") == "python" + + job = await response.parse() + assert_matches_type(AsyncCursorPage[FineTuningJobEvent], job, path=["response"]) + + assert cast(Any, response.is_closed) is True + + @parametrize + async def test_path_params_list_events(self, async_client: AsyncOpenAI) -> None: + with pytest.raises(ValueError, match=r"Expected a non-empty value for `fine_tuning_job_id` but received ''"): + await async_client.fine_tuning.jobs.with_raw_response.list_events( + "", + ) From 8f2a772198db5729d2acb315d166ec4d80a6b2f3 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 21 Aug 2026 03:54:46 +0000 Subject: [PATCH 2/3] test(api): move vector-store signature tests out of generated code (#3707) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - [x] I understand that this repository is auto-generated and my pull request may not be merged ## Changes being requested Move the three handwritten vector-store helper-signature tests into handwritten test modules, then restore the two API-resource test files to the recorded public generated snapshot. Keep each original function, decorator, comparison, and excluded-parameter set unchanged. Only four test files change. No polling, upload, runtime, dependency, API reference, compiler, or generation-metadata changes. ## Additional context & links The exact retained coverage is: - [`tests/lib/test_vector_store_file_batches.py::test_create_and_poll_method_in_sync`](https://github.com/openai/openai-python/blob/8eaeaad036a156bbd4155c6a426acffa06d13cfd/tests/lib/test_vector_store_file_batches.py#L10) keeps batch `create_and_poll` aligned with `create`. - [`tests/lib/test_vector_store_files.py::test_create_and_poll_method_in_sync`](https://github.com/openai/openai-python/blob/8eaeaad036a156bbd4155c6a426acffa06d13cfd/tests/lib/test_vector_store_files.py#L10) keeps file `create_and_poll` aligned with `create`. - [`tests/lib/test_vector_store_files.py::test_upload_and_poll_method_in_sync`](https://github.com/openai/openai-python/blob/8eaeaad036a156bbd4155c6a426acffa06d13cfd/tests/lib/test_vector_store_files.py#L20) keeps `upload_and_poll` aligned with `create`, retaining exactly the existing exclusions: `file_id`, `extra_headers`, `extra_query`, `extra_body`, and `timeout`. Each still runs for both sync and async clients: all **six original cases** are preserved. The generated API tests remain intact. Validation: - Exact-source/AST proof, including decorators and exclusions; both generated files match the public snapshot byte-for-byte. - Both Pydantic collection checks preserve all six original test IDs after mapping only the file paths. - The two handwritten modules plus both affected API-resource suites pass **226 tests under Pydantic v2 and 226 under v1**, against the checked-in API mock. - `./scripts/format` and `./scripts/lint` pass, including Ruff, Pyright, mypy, and import checks. Unrelated reporter-only formatting changes are excluded. - Verified public custom-code report: **40 → 38 mixed files**, exactly these two customizations removed and every other customization unchanged. --- .../vector_stores/test_file_batches.py | 12 --------- .../api_resources/vector_stores/test_files.py | 22 --------------- tests/lib/test_vector_store_file_batches.py | 17 ++++++++++++ tests/lib/test_vector_store_files.py | 27 +++++++++++++++++++ 4 files changed, 44 insertions(+), 34 deletions(-) create mode 100644 tests/lib/test_vector_store_file_batches.py create mode 100644 tests/lib/test_vector_store_files.py diff --git a/tests/api_resources/vector_stores/test_file_batches.py b/tests/api_resources/vector_stores/test_file_batches.py index 08def373f3..c0e9bcf57b 100644 --- a/tests/api_resources/vector_stores/test_file_batches.py +++ b/tests/api_resources/vector_stores/test_file_batches.py @@ -9,7 +9,6 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai._utils import assert_signatures_in_sync from openai.pagination import SyncCursorPage, AsyncCursorPage from openai.types.vector_stores import ( VectorStoreFile, @@ -451,14 +450,3 @@ async def test_path_params_list_files(self, async_client: AsyncOpenAI) -> None: batch_id="", vector_store_id="vector_store_id", ) - - -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: - checking_client: OpenAI | AsyncOpenAI = client if sync else async_client - - # ensure helpers do not drift from generated spec - assert_signatures_in_sync( - checking_client.vector_stores.file_batches.create, - checking_client.vector_stores.file_batches.create_and_poll, - ) diff --git a/tests/api_resources/vector_stores/test_files.py b/tests/api_resources/vector_stores/test_files.py index 94522ec5af..f6ea323bb1 100644 --- a/tests/api_resources/vector_stores/test_files.py +++ b/tests/api_resources/vector_stores/test_files.py @@ -9,7 +9,6 @@ from openai import OpenAI, AsyncOpenAI from tests.utils import assert_matches_type -from openai._utils import assert_signatures_in_sync from openai.pagination import SyncPage, AsyncPage, SyncCursorPage, AsyncCursorPage from openai.types.vector_stores import ( VectorStoreFile, @@ -626,24 +625,3 @@ async def test_path_params_content(self, async_client: AsyncOpenAI) -> None: file_id="", vector_store_id="vs_abc123", ) - - -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: - checking_client: OpenAI | AsyncOpenAI = client if sync else async_client - - assert_signatures_in_sync( - checking_client.vector_stores.files.create, - checking_client.vector_stores.files.create_and_poll, - ) - - -@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) -def test_upload_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: - checking_client: OpenAI | AsyncOpenAI = client if sync else async_client - - assert_signatures_in_sync( - checking_client.vector_stores.files.create, - checking_client.vector_stores.files.upload_and_poll, - exclude_params={"file_id", "extra_headers", "extra_query", "extra_body", "timeout"}, - ) diff --git a/tests/lib/test_vector_store_file_batches.py b/tests/lib/test_vector_store_file_batches.py new file mode 100644 index 0000000000..5165e077d2 --- /dev/null +++ b/tests/lib/test_vector_store_file_batches.py @@ -0,0 +1,17 @@ +from __future__ import annotations + +import pytest + +from openai import OpenAI, AsyncOpenAI +from openai._utils import assert_signatures_in_sync + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + # ensure helpers do not drift from generated spec + assert_signatures_in_sync( + checking_client.vector_stores.file_batches.create, + checking_client.vector_stores.file_batches.create_and_poll, + ) diff --git a/tests/lib/test_vector_store_files.py b/tests/lib/test_vector_store_files.py new file mode 100644 index 0000000000..9c4d87973e --- /dev/null +++ b/tests/lib/test_vector_store_files.py @@ -0,0 +1,27 @@ +from __future__ import annotations + +import pytest + +from openai import OpenAI, AsyncOpenAI +from openai._utils import assert_signatures_in_sync + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_create_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.vector_stores.files.create, + checking_client.vector_stores.files.create_and_poll, + ) + + +@pytest.mark.parametrize("sync", [True, False], ids=["sync", "async"]) +def test_upload_and_poll_method_in_sync(sync: bool, client: OpenAI, async_client: AsyncOpenAI) -> None: + checking_client: OpenAI | AsyncOpenAI = client if sync else async_client + + assert_signatures_in_sync( + checking_client.vector_stores.files.create, + checking_client.vector_stores.files.upload_and_poll, + exclude_params={"file_id", "extra_headers", "extra_query", "extra_body", "timeout"}, + ) From 45341061b382473ee8a8e8c796ef8819089abbb6 Mon Sep 17 00:00:00 2001 From: Alex Chang Date: Fri, 21 Aug 2026 03:58:56 +0000 Subject: [PATCH 3/3] docs(api): restore generated ChatKit API index (#3705) - [x] I understand that this repository is auto-generated and my pull request may not be merged ## Changes being requested Restore the existing ChatKit section in `api.md` from the [recorded public generated snapshot](https://github.com/openai/openai-python/blob/0d3e70da47bb645fbfd0dd16fdd37ea10ee981f5/api.md#L633). The handwritten legacy Realtime section had displaced it. This change retains that section and every other existing line, including documentation for handwritten public helpers. Only `api.md` changes: 50 lines are restored verbatim. All documented ChatKit types and methods already exist in the public SDK. No runtime code, tests, dependencies, API reference, compiler, or generation metadata changes. ## Additional context & links Validation: - Exact-byte comparison with the public generated ChatKit section. - All eight restored source links and both import examples resolve to existing public files/exports; all six documented methods exist in both sync and async resources. - The repository's `scripts/utils/ruffen-docs.py api.md` formatter and `git diff --check` pass. - The verified public custom-code report keeps 40 mixed files, with only `api.md` changed and 39 customizations untouched. Its patch shrinks from **+87/-32 to +105/-0**: the API index no longer deletes generated content. No tests are removed or relocated in this documentation-only cleanup. --- api.md | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/api.md b/api.md index c17edbb239..cf6ae87931 100644 --- a/api.md +++ b/api.md @@ -643,6 +643,56 @@ Methods: - client.beta.responses.input_tokens.count(\*\*params) -> InputTokenCountResponse +## ChatKit + +Types: + +```python +from openai.types.beta import ChatKitWorkflow +``` + +### Sessions + +Methods: + +- client.beta.chatkit.sessions.create(\*\*params) -> ChatSession +- client.beta.chatkit.sessions.cancel(session_id) -> ChatSession + +### Threads + +Types: + +```python +from openai.types.beta.chatkit import ( + ChatSession, + ChatSessionAutomaticThreadTitling, + ChatSessionChatKitConfiguration, + ChatSessionChatKitConfigurationParam, + ChatSessionExpiresAfterParam, + ChatSessionFileUpload, + ChatSessionHistory, + ChatSessionRateLimits, + ChatSessionRateLimitsParam, + ChatSessionStatus, + ChatSessionWorkflowParam, + ChatKitAttachment, + ChatKitResponseOutputText, + ChatKitThread, + ChatKitThreadAssistantMessageItem, + ChatKitThreadItemList, + ChatKitThreadUserMessageItem, + ChatKitWidgetItem, + ThreadDeleteResponse, +) +``` + +Methods: + +- client.beta.chatkit.threads.retrieve(thread_id) -> ChatKitThread +- client.beta.chatkit.threads.list(\*\*params) -> SyncConversationCursorPage[ChatKitThread] +- client.beta.chatkit.threads.delete(thread_id) -> ThreadDeleteResponse +- client.beta.chatkit.threads.list_items(thread_id, \*\*params) -> SyncConversationCursorPage[Data] + ## Realtime Types: