From c4b2d9f53bdafca08eb137285834687524ad6e14 Mon Sep 17 00:00:00 2001 From: chengyongru Date: Wed, 6 May 2026 15:45:47 +0800 Subject: [PATCH] fix(transcription): address review nits on PR #3253 - Correct api_key type hint to str | None in _post_transcription_with_retry - Remove unreachable final return "" - Fix test_openai_missing_api_key_short_circuits to actually test missing-key path (use audio_file fixture so file exists) - Fix PermissionError patch for Windows (patch class method instead of instance attribute) --- nanobot/providers/transcription.py | 4 +--- tests/providers/test_transcription.py | 9 ++++----- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/nanobot/providers/transcription.py b/nanobot/providers/transcription.py index 25e09dab7..b4c71929e 100644 --- a/nanobot/providers/transcription.py +++ b/nanobot/providers/transcription.py @@ -26,7 +26,7 @@ _RETRYABLE_EXCEPTIONS = ( async def _post_transcription_with_retry( url: str, *, - api_key: str, + api_key: str | None, path: Path, model: str, provider_label: str, @@ -116,8 +116,6 @@ async def _post_transcription_with_retry( return "" return payload.get("text", "") - return "" - class OpenAITranscriptionProvider: """Voice transcription provider using OpenAI's Whisper API.""" diff --git a/tests/providers/test_transcription.py b/tests/providers/test_transcription.py index 288290a92..5fd10d552 100644 --- a/tests/providers/test_transcription.py +++ b/tests/providers/test_transcription.py @@ -134,14 +134,13 @@ async def test_groq_does_not_retry_on_auth_error(audio_file: Path) -> None: @pytest.mark.asyncio -async def test_openai_missing_api_key_short_circuits(tmp_path: Path) -> None: - provider = OpenAITranscriptionProvider(api_key=None) - # Ensure env var doesn't accidentally satisfy it. +async def test_openai_missing_api_key_short_circuits(audio_file: Path) -> None: + """Missing API key short-circuits before any HTTP call, even when the file exists.""" with patch.dict("os.environ", {}, clear=True): provider = OpenAITranscriptionProvider(api_key=None) post = AsyncMock() with patch("httpx.AsyncClient.post", post): - assert await provider.transcribe(tmp_path / "voice.ogg") == "" + assert await provider.transcribe(audio_file) == "" assert post.await_count == 0 @@ -159,7 +158,7 @@ async def test_returns_empty_when_file_unreadable(audio_file: Path) -> None: """Existing file that cannot be read (PermissionError/OSError): "" with no HTTP attempt.""" provider = OpenAITranscriptionProvider(api_key="sk-test") post = AsyncMock() - with patch.object(Path, "read_bytes", side_effect=PermissionError("denied")), patch( + with patch("pathlib.Path.read_bytes", side_effect=PermissionError("denied")), patch( "httpx.AsyncClient.post", post ): result = await provider.transcribe(audio_file)