Skip to content

Migrate Python API to websockets new asyncio API (>=14.0)#607

Open
mkusaka wants to merge 1 commit into
gnachman:masterfrom
mkusaka:refactor/websockets-new-api
Open

Migrate Python API to websockets new asyncio API (>=14.0)#607
mkusaka wants to merge 1 commit into
gnachman:masterfrom
mkusaka:refactor/websockets-new-api

Conversation

@mkusaka
Copy link
Copy Markdown
Contributor

@mkusaka mkusaka commented Mar 5, 2026

Follow-up to #604. Migrates connection.py from the legacy websockets API to the new asyncio-based API introduced in websockets 14.0, as discussed with @gnachman.

Why websockets>=14.0?

websockets 14.0 is the first version where the new asyncio implementation became the default (changelog). In 13.0, the new implementation was introduced but opt-in; in 14.0, websockets.connect and websockets.unix_connect point to the new API by default, and the legacy implementation was deprecated.

Migration references

Changes

connection.py

  • Remove the legacy/new API compatibility shim (try: import websockets.legacy.client / except)
  • InvalidStatusCodeInvalidStatus (access via e.response.status_code instead of e.status_code) — InvalidStatusCode is legacy-only
  • extra_headers=additional_headers=new API parameter name
  • response_headersresponse.headers — new API uses ClientConnection.response object
  • websockets.legacy.client.connectwebsockets.connect
  • websockets.legacy.client.unix_connectwebsockets.unix_connect
  • Remove all # type: ignore comments (no longer needed)

setup.py

  • Pin websockets>=14.0 (first version where new asyncio API is the default)

tests/test_connection.py (new, 12 tests)

  • TestIterm2ProtocolVersion — version header parsing (4 tests)
  • TestInvalidStatusHandling — 406/500/401 error handling in async_connect (4 tests)
  • TestAsyncCreate — 406/500 error handling in async_create (2 tests)
  • TestConnectCoroutineArgsadditional_headers parameter passing for TCP and Unix (2 tests)

Test plan

  • pytest tests/test_connection.py — 12 passed
  • pytest tests/ — 154 passed (no regressions)
  • Smoke-tested against a running iTerm2 instance with the following script:
    import iterm2
    
    async def main(connection):
        app = await iterm2.async_get_app(connection)
        print(f"Protocol version: {connection.iterm2_protocol_version}")
        print(f"Windows: {len(app.windows)}")
        for w in app.windows:
            for tab in w.tabs:
                for session in tab.sessions:
                    print(f"  Session: {session.session_id}")
    
    iterm2.run_until_complete(main)
    cd api/library/python/iterm2
    uvx --with . python tests/smoke_test.py
    Result: connected successfully, protocol version (1, 11), 4 windows / 16 sessions listed

Remove the legacy/new API compatibility shim and migrate directly to the
websockets 14.0+ API:
- InvalidStatusCode → InvalidStatus (with response.status_code)
- extra_headers → additional_headers
- response_headers → response.headers
- websockets.legacy.client.connect → websockets.connect
- websockets.legacy.client.unix_connect → websockets.unix_connect
- Pin websockets>=14.0 in setup.py

Add tests for connection module covering protocol version parsing,
InvalidStatus error handling (406/500/401), async_create error paths,
and argument passing to connect methods.
@gnachman
Copy link
Copy Markdown
Owner

gnachman commented Mar 6, 2026

Unfortunately it looks like we still have to support older versions of Python, while websockets 14 needs Python 3.9. For compatibility reasons, scripts are generally locked at the major version they were originally implemented in. That could be as old as Python 3.7. I don't have a good plan to get people off of ancient Pythons. Do you think we could maintain a backward compatibility codepath?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants