fix: preserve explicit API key semantics - #778
Conversation
|
dg-coreylweathers
left a comment
There was a problem hiding this comment.
What this PR does
PR #767 made the SDK re-read DEEPGRAM_API_KEY when the client is constructed, but its check treated an omitted api_key argument and an explicit api_key=None as the same thing, so passing None on purpose silently picked up whatever key was in the process environment. This PR changes the check ("api_key" not in kwargs) in both the sync and async clients so explicit None is rejected with an ApiError at construction — which is exactly what the released 7.8.0 does today.
What I checked
- Does explicit
Noneactually raise? Yes — it now passes through to the generated base client, which raisesApiErrorwhen the key isNone, and that client's parameters are keyword-only, so the membership check cannot be bypassed positionally. - Did the regression ever reach a release? No — #767 merged after 7.8.0 shipped, so no released version ever had the explicit-
None-falls-back-to-env behavior; #767 and this fix will ship together. - Are the new tests real? Yes — the rewritten load_dotenv-ordering test spawns a subprocess with the key stripped from the environment, which is the only way to genuinely reproduce "imported without a key" (the old in-process test could not). The new explicit-
Nonetest fails on currentmain, so it proves the fix rather than restating it. - Everything else passed: CI green across Python 3.10–3.13, the
access_tokenpath is unchanged and still covered, and no README/docs/example anywhere describesapi_key=Noneas an environment-fallback idiom.
No changes requested.
dg-coreylweathers
left a comment
There was a problem hiding this comment.
What this PR does
PR #767 made the SDK re-read DEEPGRAM_API_KEY when the client is constructed, but its check treated an omitted api_key argument and an explicit api_key=None as the same thing, so passing None on purpose silently picked up whatever key was in the process environment. This PR changes the check ("api_key" not in kwargs) in both the sync and async clients so explicit None is rejected with an ApiError at construction — which is exactly what the released 7.8.0 does today.
What I checked
- Does explicit
Noneactually raise? Yes — it now passes through to the generated base client, which raisesApiErrorwhen the key isNone, and that client's parameters are keyword-only, so the membership check cannot be bypassed positionally. - Did the regression ever reach a release? No — #767 merged after 7.8.0 shipped, so no released version ever had the explicit-
None-falls-back-to-env behavior; #767 and this fix will ship together. - Are the new tests real? Yes — the rewritten load_dotenv-ordering test spawns a subprocess with the key stripped from the environment, which is the only way to genuinely reproduce "imported without a key" (the old in-process test could not). The new explicit-
Nonetest fails on currentmain, so it proves the fix rather than restating it. - Everything else passed: CI green across Python 3.10–3.13, the
access_tokenpath is unchanged and still covered, and no README/docs/example anywhere describesapi_key=Noneas an environment-fallback idiom.
No changes requested.
🤖 I have created a release *beep* *boop* --- ## [7.8.1](v7.8.0...v7.8.1) (2026-09-03) ### Bug Fixes * **TextBuilder:** `ssml_to_deepgram()` now preserves a `<phoneme>` pronunciation when its valid `ph` and `alphabet` attributes appear in either order. ([#741](#741)) ([7fd4b63](7fd4b63)) * **Credentials:** Explicitly passing `api_key=None` continues to disable ambient `DEEPGRAM_API_KEY` lookup, which is important for multi-tenant and test environments. ([#778](#778)) ([e675990](e675990)) * **Credentials:** `DeepgramClient()` and `AsyncDeepgramClient()` now resolve `DEEPGRAM_API_KEY` when constructed, so `load_dotenv()` can run after importing the SDK. Closes [#734](#734). ([#767](#767)) ([ec362ec](ec362ec)) * **Custom transports:** Speak V2 WebSocket connections now honor `transport_factory`, matching the routing behavior of other WebSocket APIs for proxies, test doubles, and custom-hosted transports. ([#766](#766)) ([0980663](0980663)) ### Documentation * **Transcription:** Clarified that Nova-3 assumes English when `language` is omitted; non-English and multilingual audio require an explicit language such as `fr` or `multi`. ([#771](#771)) ([4574337](4574337)) * **Examples:** Added Listen V1 live microphone transcription with optional `sounddevice`, device selection, bounded audio buffering, transcript output, and clean Ctrl-C shutdown. ([#780](#780)) ([08f0471](08f0471)) * **Examples:** Added a resilient Listen V1 live transcription pattern with exponential backoff, reconnect-aware audio buffering, timestamp continuity, and clean shutdown. ([#776](#776)) ([96b2d11](96b2d11)) * **Examples:** Added an application-owned Voice Agent session recorder that serializes received transcripts, function calls, and latency reports as JSON while leaving consent, redaction, retention, and storage policy to the application. Closes [#775](#775). ([#781](#781)) ([30ad152](30ad152)) * **Text-to-Speech:** Corrected streaming synthesis snippets to iterate the response byte chunks instead of accessing a nonexistent `.stream` attribute. ([#749](#749)) ([178724e](178724e)) --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). --------- Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Greg Holmes <greg.holmes@deepgram.com>
Summary
DEEPGRAM_API_KEYat construction only when theapi_keyargument is omittedapi_key=Nonerejects authentication instead of silently using an ambient process credentialDEEPGRAM_API_KEYNonebehaviorFollow-up to #767 and #734.
Why
#767 correctly fixed delayed environment loading, but its
kwargs.get("api_key") is Nonecheck treated an omitted argument and explicitNoneas equivalent. In tests, multi-tenant services, or applications intentionally suppressing ambient authentication, explicitNonemust not activate a process-wide credential.Verification
1020 passed, 1 skippedmypy src: clean across 901 source filesgit diff --check: clean