Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [4.0.8] - 2025-06-30

- Patch WebsocketClient to work with any websockets version >= 10.0

## [4.0.7] - 2025-06-19

- Support requesting a temporary token (JWT) with region and client ref
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
4.0.7
4.0.8
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
websockets>=14.0
websockets>=10.0
httpx[http2]~=0.23
polling2~=0.5
toml~=0.10.2
Expand Down
28 changes: 22 additions & 6 deletions speechmatics/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,18 @@
UsageMode,
)

try:
# Try to import from new websockets >=13.0
from websockets.asyncio.client import connect

WS_HEADERS_KEY = "additional_headers"
except ImportError:
# Fall back to legacy websockets
from websockets.legacy.client import connect

WS_HEADERS_KEY = "extra_headers"


LOGGER = logging.getLogger(__name__)

# If the logging level is set to DEBUG then websockets logs very verbosely,
Expand Down Expand Up @@ -613,14 +625,18 @@ async def run(
parsed_url._replace(path=url_path, query=updated_query)
)

ws_kwargs = {
WS_HEADERS_KEY: extra_headers,
"ssl": self.connection_settings.ssl_context,
"ping_timeout": self.connection_settings.ping_timeout_seconds,
# Don't limit the max. size of incoming messages
"max_size": None,
}

try:
async with websockets.connect( # pylint: disable=no-member
async with connect(
updated_url,
ssl=self.connection_settings.ssl_context,
ping_timeout=self.connection_settings.ping_timeout_seconds,
# Don't limit the max. size of incoming messages
max_size=None,
additional_headers=extra_headers,
**ws_kwargs,
) as self.websocket:
await self._communicate(stream, audio_settings)
finally:
Expand Down
33 changes: 23 additions & 10 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@
import pytest

from pytest_httpx import HTTPXMock
import websockets
from speechmatics import client
from speechmatics.batch_client import BatchClient
from speechmatics.exceptions import ForceEndSession
Expand All @@ -25,6 +24,17 @@

from tests.utils import path_to_test_resource, default_ws_client_setup

try:
# Try to import from new websockets >= 13
from websockets.asyncio.client import connect

WS_HEADERS_KEY = "additional_headers"
except ImportError:
# Fall back to legacy websockets
from websockets.legacy.client import connect

WS_HEADERS_KEY = "extra_headers"


def test_json_utf8():
@client.json_utf8
Expand Down Expand Up @@ -229,13 +239,16 @@ async def test_send_message(mock_server, message_type: str, message_data: Any):
"""
ws_client, _, _ = default_ws_client_setup(mock_server.url)
ws_client.session_running = True

async with websockets.connect(
ws_kwargs = {
"ssl": ws_client.connection_settings.ssl_context,
"ping_timeout": ws_client.connection_settings.ping_timeout_seconds,
"max_size": None,
WS_HEADERS_KEY: None,
}

async with connect(
mock_server.url,
ssl=ws_client.connection_settings.ssl_context,
ping_timeout=ws_client.connection_settings.ping_timeout_seconds,
max_size=None,
additional_headers=None,
**ws_kwargs,
) as ws_client.websocket:
await ws_client.send_message(message_type, message_data)
assert message_type in [
Expand Down Expand Up @@ -387,7 +400,7 @@ async def mock_connect(*_, **__):

mock_logger_error_method = MagicMock()

with patch("websockets.connect", mock_connect):
with patch("speechmatics.client.connect", mock_connect):
with patch.object(client.LOGGER, "error", mock_logger_error_method):
try:
ws_client.run_synchronously(
Expand All @@ -411,7 +424,7 @@ def call_exit(*args, **kwargs):
mock_server.url
)
stream = MagicMock()
with patch("websockets.connect", connect_mock):
with patch("speechmatics.client.connect", connect_mock):
try:
ws_client.run_synchronously(
transcription_config=transcription_config,
Expand All @@ -422,7 +435,7 @@ def call_exit(*args, **kwargs):
except Exception:
assert len(connect_mock.mock_calls) == 1
assert (
connect_mock.mock_calls[0][2]["additional_headers"] == extra_headers
connect_mock.mock_calls[0][2][WS_HEADERS_KEY] == extra_headers
), f"Extra headers don't appear in the call list = {connect_mock.mock_calls}"


Expand Down