Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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-07-03

- 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