diff --git a/src/openai/_utils/_utils.py b/src/openai/_utils/_utils.py index 90494748cc..10f7dec3c1 100644 --- a/src/openai/_utils/_utils.py +++ b/src/openai/_utils/_utils.py @@ -276,8 +276,7 @@ def wrapper(*args: object, **kwargs: object) -> object: else: assert len(variants) > 0 - # TODO: this error message is not deterministic - missing = list(set(variants[0]) - given_params) + missing = [arg for arg in variants[0] if arg not in given_params] if len(missing) > 1: msg = f"Missing required arguments: {human_join([quote(arg) for arg in missing])}" else: diff --git a/tests/test_required_args.py b/tests/test_required_args.py index 5d1a5224ff..45ed5a8228 100644 --- a/tests/test_required_args.py +++ b/tests/test_required_args.py @@ -2,6 +2,7 @@ import pytest +from openai import OpenAI, AsyncOpenAI from openai._utils import required_args @@ -47,18 +48,16 @@ def foo(a: str = "", *, b: str = "", c: str = "") -> str | None: assert foo(a="a", b="b", c="c") == "a b c" - error_message = r"Missing required arguments.*" - - with pytest.raises(TypeError, match=error_message): + with pytest.raises(TypeError, match=r"Missing required arguments: 'a', 'b' or 'c'"): foo() - with pytest.raises(TypeError, match=error_message): + with pytest.raises(TypeError, match=r"Missing required arguments: 'b' or 'c'"): foo(a="a") - with pytest.raises(TypeError, match=error_message): + with pytest.raises(TypeError, match=r"Missing required arguments: 'a' or 'c'"): foo(b="b") - with pytest.raises(TypeError, match=error_message): + with pytest.raises(TypeError, match=r"Missing required arguments: 'a' or 'b'"): foo(c="c") with pytest.raises(TypeError, match=r"Missing required argument: 'a'"): @@ -109,3 +108,54 @@ def foo(*, a: str | None = None, b: str | None = None, c: str | None = None) -> assert foo(a=None, b="bar") == "bar" assert foo(c=None) is None assert foo(c="foo") == "foo" + + +def test_sync_resource_completions_create_missing_prompt(client: OpenAI) -> None: + with pytest.raises(TypeError, match=r"Expected either .*'model'.*'prompt'.*"): + client.completions.create(model="gpt-3.5-turbo-instruct") # type: ignore[call-arg] + + +def test_sync_resource_images_edit_missing_prompt(client: OpenAI) -> None: + with pytest.raises(TypeError, match=r"Expected either .*'image'.*'prompt'.*"): + client.images.edit(image=b"Example data") # type: ignore[call-arg] + + +def test_sync_resource_audio_transcriptions_create_missing_model(client: OpenAI) -> None: + with pytest.raises(TypeError, match=r"Expected either .*'file'.*'model'.*"): + client.audio.transcriptions.create(file=b"Example data") # type: ignore[call-arg] + + +def test_sync_resource_beta_threads_create_and_run_missing_assistant_id(client: OpenAI) -> None: + error_message = r"Missing required arguments; Expected either \('assistant_id'\) or \('assistant_id' and 'stream'\) arguments to be given" + + with pytest.warns(DeprecationWarning, match="The Assistants API is deprecated"): + with pytest.raises(TypeError, match=error_message): + client.beta.threads.create_and_run() # type: ignore[call-arg] + + +def test_sync_resource_beta_threads_runs_create_missing_assistant_id(client: OpenAI) -> None: + error_message = r"Missing required arguments; Expected either \('assistant_id'\) or \('assistant_id' and 'stream'\) arguments to be given" + + with pytest.warns(DeprecationWarning, match="The Assistants API is deprecated"): + with pytest.raises(TypeError, match=error_message): + client.beta.threads.runs.create("thread_123") # type: ignore[call-arg] + + +async def test_async_resource_chat_completions_create_missing_messages(async_client: AsyncOpenAI) -> None: + with pytest.raises(TypeError, match=r"Expected either .*'messages'.*'model'.*"): + async_client.chat.completions.create(model="gpt-5.4") # type: ignore[call-arg] + + +async def test_async_resource_images_generate_missing_prompt(async_client: AsyncOpenAI) -> None: + with pytest.raises(TypeError, match=r"Expected either .*'prompt'.*"): + async_client.images.generate() # type: ignore[call-arg] + + +async def test_async_resource_beta_threads_runs_submit_tool_outputs_missing_tool_outputs( + async_client: AsyncOpenAI, +) -> None: + error_message = r"Missing required arguments; Expected either \('thread_id' and 'tool_outputs'\) or \('thread_id', 'stream' and 'tool_outputs'\) arguments to be given" + + with pytest.warns(DeprecationWarning, match="The Assistants API is deprecated"): + with pytest.raises(TypeError, match=error_message): + async_client.beta.threads.runs.submit_tool_outputs("run_123", thread_id="thread_123") # type: ignore[call-arg]