From 23d888a17e0aa27965f868e9567213a13af44918 Mon Sep 17 00:00:00 2001 From: Mark Larah Date: Wed, 18 Mar 2026 18:25:00 -0700 Subject: [PATCH] Fix typing of TransportQueryError.errors from List[Any] to List[GraphQLError] - Change `errors` type annotation in `TransportQueryError` from `Optional[List[Any]]` to `Optional[List[GraphQLError]]` - Wrap raw dict payload in `GraphQLError` in `websockets_protocol.py` so all error paths produce `GraphQLError` objects consistently - Update test assertions to use `GraphQLError` attribute access (`.message`, `.extensions`) instead of dict indexing (`["message"]`) - Add `extensions is not None` guards for mypy narrowing This reduces the total mypy error count from 24 to 10 (fixing 14 pre-existing type errors in websocket exception tests). Co-Authored-By: Claude Opus 4.6 --- gql/transport/exceptions.py | 6 ++++-- gql/transport/websockets_protocol.py | 11 +++++++++-- tests/test_aiohttp_websocket_exceptions.py | 8 +++++--- tests/test_aiohttp_websocket_graphqlws_exceptions.py | 8 +++++--- tests/test_graphqlws_exceptions.py | 8 +++++--- tests/test_websocket_exceptions.py | 8 +++++--- 6 files changed, 33 insertions(+), 16 deletions(-) diff --git a/gql/transport/exceptions.py b/gql/transport/exceptions.py index 0049d5c2..151e1a95 100644 --- a/gql/transport/exceptions.py +++ b/gql/transport/exceptions.py @@ -1,5 +1,7 @@ from typing import Any, List, Optional +from graphql import GraphQLError + class TransportError(Exception): """Base class for all the Transport exceptions""" @@ -34,7 +36,7 @@ class TransportQueryError(TransportError): """ query_id: Optional[int] - errors: Optional[List[Any]] + errors: Optional[List[GraphQLError]] data: Optional[Any] extensions: Optional[Any] @@ -42,7 +44,7 @@ def __init__( self, msg: str, query_id: Optional[int] = None, - errors: Optional[List[Any]] = None, + errors: Optional[List[GraphQLError]] = None, data: Optional[Any] = None, extensions: Optional[Any] = None, ): diff --git a/gql/transport/websockets_protocol.py b/gql/transport/websockets_protocol.py index 1ccf744e..0052af20 100644 --- a/gql/transport/websockets_protocol.py +++ b/gql/transport/websockets_protocol.py @@ -4,7 +4,7 @@ from contextlib import suppress from typing import Any, Dict, List, Optional, Tuple, Union -from graphql import ExecutionResult +from graphql import ExecutionResult, GraphQLError from ..graphql_request import GraphQLRequest from .common.adapters.connection import AdapterConnection @@ -382,7 +382,14 @@ def _parse_answer_apollo( elif answer_type == "error": raise TransportQueryError( - str(payload), query_id=answer_id, errors=[payload] + str(payload), + query_id=answer_id, + errors=[ + GraphQLError( + payload.get("message", str(payload)), + extensions=payload.get("extensions"), + ) + ], ) elif answer_type == "ka": diff --git a/tests/test_aiohttp_websocket_exceptions.py b/tests/test_aiohttp_websocket_exceptions.py index 2fb6722c..d35010b5 100644 --- a/tests/test_aiohttp_websocket_exceptions.py +++ b/tests/test_aiohttp_websocket_exceptions.py @@ -55,7 +55,8 @@ async def test_aiohttp_websocket_invalid_query(aiohttp_client_and_server, query_ error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" invalid_subscription_str = """ @@ -97,7 +98,8 @@ async def test_aiohttp_websocket_invalid_subscription( error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" connection_error_server_answer = ( @@ -205,7 +207,7 @@ async def monkey_patch_send_query( error = exception.errors[0] - assert error["message"] == "Must provide document" + assert error.message == "Must provide document" not_json_answer = ["BLAHBLAH"] diff --git a/tests/test_aiohttp_websocket_graphqlws_exceptions.py b/tests/test_aiohttp_websocket_graphqlws_exceptions.py index 52bc27a4..e1627d2c 100644 --- a/tests/test_aiohttp_websocket_graphqlws_exceptions.py +++ b/tests/test_aiohttp_websocket_graphqlws_exceptions.py @@ -55,7 +55,8 @@ async def test_aiohttp_websocket_graphqlws_invalid_query( error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" invalid_subscription_str = """ @@ -99,7 +100,8 @@ async def test_aiohttp_websocket_graphqlws_invalid_subscription( error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" async def server_no_ack(ws): @@ -159,7 +161,7 @@ async def test_aiohttp_websocket_graphqlws_sending_invalid_query( error = exception.errors[0] assert ( - error["message"] + error.message == 'Cannot query field "helo" on type "Query". Did you mean "hello"?' ) diff --git a/tests/test_graphqlws_exceptions.py b/tests/test_graphqlws_exceptions.py index 6f30c8da..758e0dd1 100644 --- a/tests/test_graphqlws_exceptions.py +++ b/tests/test_graphqlws_exceptions.py @@ -53,7 +53,8 @@ async def test_graphqlws_invalid_query(client_and_graphqlws_server, query_str): error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" invalid_subscription_str = """ @@ -95,7 +96,8 @@ async def test_graphqlws_invalid_subscription(client_and_graphqlws_server, query error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" async def server_no_ack(ws): @@ -151,7 +153,7 @@ async def test_graphqlws_sending_invalid_query(client_and_graphqlws_server): error = exception.errors[0] assert ( - error["message"] + error.message == 'Cannot query field "helo" on type "Query". Did you mean "hello"?' ) diff --git a/tests/test_websocket_exceptions.py b/tests/test_websocket_exceptions.py index b6169468..4ed5c34b 100644 --- a/tests/test_websocket_exceptions.py +++ b/tests/test_websocket_exceptions.py @@ -56,7 +56,8 @@ async def test_websocket_invalid_query(client_and_server, query_str): error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" invalid_subscription_str = """ @@ -96,7 +97,8 @@ async def test_websocket_invalid_subscription(client_and_server, query_str): error = exception.errors[0] - assert error["extensions"]["code"] == "INTERNAL_SERVER_ERROR" + assert error.extensions is not None + assert error.extensions["code"] == "INTERNAL_SERVER_ERROR" connection_error_server_answer = ( @@ -200,7 +202,7 @@ async def monkey_patch_send_query( error = exception.errors[0] - assert error["message"] == "Must provide document" + assert error.message == "Must provide document" not_json_answer = ["BLAHBLAH"]