diff --git a/src/deepgram/transport.py b/src/deepgram/transport.py index a7897725..b92e3dff 100644 --- a/src/deepgram/transport.py +++ b/src/deepgram/transport.py @@ -27,7 +27,7 @@ # --------------------------------------------------------------------------- # Module paths that contain the websocket references we need to patch. -# All 8 are auto-generated by Fern — we never modify their source. +# All 10 are auto-generated by Fern — we never modify their source. # --------------------------------------------------------------------------- _TARGET_MODULES = [ "deepgram.listen.v1.raw_client", @@ -36,6 +36,8 @@ "deepgram.listen.v2.client", "deepgram.speak.v1.raw_client", "deepgram.speak.v1.client", + "deepgram.speak.v2.raw_client", + "deepgram.speak.v2.client", "deepgram.agent.v1.raw_client", "deepgram.agent.v1.client", ] diff --git a/tests/custom/test_transport.py b/tests/custom/test_transport.py index 84a262f7..80ceff4b 100644 --- a/tests/custom/test_transport.py +++ b/tests/custom/test_transport.py @@ -2,11 +2,13 @@ import json import sys -from typing import Any, Dict, Iterator, List +from pathlib import Path +from typing import Any, Dict, Iterator, List, Set from unittest.mock import MagicMock import pytest +import deepgram from deepgram.transport import ( AsyncTransport, SyncTransport, @@ -530,3 +532,50 @@ def test_async_transport_factory_auto_disables_reconnect(self): from deepgram.client import AsyncDeepgramClient client = AsyncDeepgramClient(api_key="test-key", transport_factory=factory) assert client.reconnect is False + + +# --------------------------------------------------------------------------- +# _TARGET_MODULES completeness +# --------------------------------------------------------------------------- + +_PATCHED_SYMBOLS = ("websockets_sync_client", "websockets_client_connect") + + +def _discover_websocket_modules() -> Set[str]: + """Return every `deepgram` module that references a patchable websocket symbol. + + Derived from the package source, deliberately not from `_TARGET_MODULES`. A + check that iterates `_TARGET_MODULES` can only confirm the list is internally + consistent; it cannot detect a websocket client missing from the list, + because the missing entry is never iterated. + """ + package_root = Path(deepgram.__file__).parent + discovered: Set[str] = set() + + for path in sorted(package_root.rglob("*.py")): + # transport.py names both symbols as its patch targets, so including it + # here would make the scan match itself. + if path.name == "transport.py": + continue + + source = path.read_text(encoding="utf-8") + if any(symbol in source for symbol in _PATCHED_SYMBOLS): + relative = path.relative_to(package_root).with_suffix("") + discovered.add(".".join(("deepgram",) + relative.parts)) + + return discovered + + +class TestTargetModuleCompleteness: + def test_every_websocket_module_is_registered_for_patching(self): + missing = sorted(_discover_websocket_modules() - set(_TARGET_MODULES)) + + assert not missing, ( + "websocket client module(s) absent from _TARGET_MODULES, so a custom " + "transport_factory is silently not applied to them: " + ", ".join(missing) + ) + + def test_discovery_locates_a_known_websocket_module(self): + # Guards the guard: if the scan silently found nothing, the completeness + # check above would pass vacuously. + assert "deepgram.listen.v1.raw_client" in _discover_websocket_modules()