Skip to content

Commit 39dfa0f

Browse files
committed
Updates based on feedback
1 parent 70100ee commit 39dfa0f

File tree

6 files changed

+35
-161
lines changed

6 files changed

+35
-161
lines changed

codegen/core/src/main/java/software/amazon/smithy/python/codegen/HttpProtocolTestGenerator.java

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -619,8 +619,6 @@ private void writeUtilStubs(Symbol serviceSymbol) {
619619
writer.addImport("smithy_http", "tuples_to_fields");
620620
writer.addImport("smithy_http.aio", "HTTPResponse", "_HTTPResponse");
621621
writer.addImport("smithy_core.aio.utils", "async_list");
622-
writer.addImport("smithy_core.aio.interfaces", "ClientErrorInfo");
623-
writer.addStdlibImport("typing", "Any");
624622

625623
writer.write("""
626624
class $1L($2T):
@@ -636,9 +634,7 @@ class $3L:
636634
def __init__(self, *, client_config: HTTPClientConfiguration | None = None):
637635
self._client_config = client_config
638636
639-
def get_error_info(self, exception: Exception, **kwargs: Any) -> ClientErrorInfo:
640-
\"\"\"Get information about an exception.\"\"\"
641-
return ClientErrorInfo(is_timeout_error=False)
637+
TIMEOUT_EXCEPTIONS = ()
642638
643639
async def send(
644640
self, request: HTTPRequest, *, request_config: HTTPRequestConfiguration | None = None
@@ -663,9 +659,7 @@ def __init__(
663659
self.fields = tuples_to_fields(headers or [])
664660
self.body = body
665661
666-
def get_error_info(self, exception: Exception, **kwargs: Any) -> ClientErrorInfo:
667-
\"\"\"Get information about an exception.\"\"\"
668-
return ClientErrorInfo(is_timeout_error=False)
662+
TIMEOUT_EXCEPTIONS = ()
669663
670664
async def send(
671665
self, request: HTTPRequest, *, request_config: HTTPRequestConfiguration | None = None

packages/smithy-core/src/smithy_core/aio/client.py

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from collections.abc import Awaitable, Callable, Sequence
77
from copy import copy
88
from dataclasses import dataclass, field, replace
9-
from typing import TYPE_CHECKING, Any, cast
9+
from typing import TYPE_CHECKING, Any
1010

1111
from .. import URI
1212
from ..auth import AuthParams
@@ -32,7 +32,6 @@
3232
ClientProtocol,
3333
ClientTransport,
3434
EndpointResolver,
35-
ErrorClassifyingTransport,
3635
Request,
3736
Response,
3837
)
@@ -469,15 +468,10 @@ async def _handle_attempt[I: SerializeableShape, O: DeserializeableShape](
469468
request=request_context.transport_request
470469
)
471470
except Exception as e:
472-
if hasattr(self.transport, "get_error_info"):
473-
classifying_transport = cast(
474-
ErrorClassifyingTransport[TRequest, TResponse], self.transport
475-
)
476-
error_info = classifying_transport.get_error_info(e)
477-
if error_info.is_timeout_error:
478-
raise ClientTimeoutError(
479-
message=f"Client timeout occurred: {e}"
480-
) from e
471+
if isinstance(e, self.transport.TIMEOUT_EXCEPTIONS):
472+
raise ClientTimeoutError(
473+
message=f"Client timeout occurred: {e}"
474+
) from e
481475
raise
482476

483477
_LOGGER.debug("Received response: %s", transport_response)

packages/smithy-core/src/smithy_core/aio/interfaces/__init__.py

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22
# SPDX-License-Identifier: Apache-2.0
33
from collections.abc import AsyncIterable, Callable
4-
from dataclasses import dataclass
54
from typing import TYPE_CHECKING, Any, Protocol, runtime_checkable
65

76
from ...documents import TypeRegistry
@@ -11,15 +10,6 @@
1110
from ...interfaces import StreamingBlob as SyncStreamingBlob
1211
from .eventstream import EventPublisher, EventReceiver
1312

14-
15-
@dataclass(frozen=True)
16-
class ClientErrorInfo:
17-
"""Information about an error from a transport."""
18-
19-
is_timeout_error: bool
20-
"""Whether this error represents a timeout condition."""
21-
22-
2313
if TYPE_CHECKING:
2414
from typing_extensions import TypeForm
2515

@@ -96,32 +86,16 @@ async def resolve_endpoint(self, params: EndpointResolverParams[Any]) -> Endpoin
9686

9787

9888
class ClientTransport[I: Request, O: Response](Protocol):
99-
"""Protocol-agnostic representation of a client transport (e.g. an HTTP client)."""
100-
101-
async def send(self, request: I) -> O:
102-
"""Send a request over the transport and receive the response."""
103-
...
104-
89+
"""Protocol-agnostic representation of a client transport (e.g. an HTTP client).
10590
106-
class ErrorClassifyingTransport[I: Request, O: Response](
107-
ClientTransport[I, O], Protocol
108-
):
109-
"""A client transport that can classify errors for retry and timeout detection.
110-
111-
Transport implementations should implement this protocol if they can determine
112-
which exceptions represent timeout conditions or other classifiable error types.
91+
Transports must define TIMEOUT_EXCEPTIONS as a tuple of exception types that
92+
are raised when a timeout occurs.
11393
"""
11494

115-
def get_error_info(self, exception: Exception, **kwargs: Any) -> ClientErrorInfo:
116-
"""Get information about an exception.
117-
118-
Args:
119-
exception: The exception to analyze
120-
**kwargs: Additional context for analysis
95+
TIMEOUT_EXCEPTIONS: tuple[type[Exception], ...]
12196

122-
Returns:
123-
ClientErrorInfo with error classification details.
124-
"""
97+
async def send(self, request: I) -> O:
98+
"""Send a request over the transport and receive the response."""
12599
...
126100

127101

packages/smithy-http/src/smithy_http/aio/aiohttp.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
except ImportError:
2121
HAS_AIOHTTP = False # type: ignore
2222

23-
from smithy_core.aio.interfaces import ClientErrorInfo, StreamingBlob
23+
from smithy_core.aio.interfaces import StreamingBlob
2424
from smithy_core.aio.types import AsyncBytesReader
2525
from smithy_core.aio.utils import async_list
2626
from smithy_core.exceptions import MissingDependencyError
@@ -52,11 +52,7 @@ def __post_init__(self) -> None:
5252
class AIOHTTPClient(HTTPClient):
5353
"""Implementation of :py:class:`.interfaces.HTTPClient` using aiohttp."""
5454

55-
def get_error_info(self, exception: Exception, **kwargs: Any) -> ClientErrorInfo:
56-
if isinstance(exception, TimeoutError):
57-
return ClientErrorInfo(is_timeout_error=True)
58-
59-
return ClientErrorInfo(is_timeout_error=False)
55+
TIMEOUT_EXCEPTIONS = (TimeoutError,)
6056

6157
def __init__(
6258
self,

packages/smithy-http/src/smithy_http/aio/crt.py

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535

3636
from smithy_core import interfaces as core_interfaces
3737
from smithy_core.aio import interfaces as core_aio_interfaces
38-
from smithy_core.aio.interfaces import ClientErrorInfo
3938
from smithy_core.aio.types import AsyncBytesReader
4039
from smithy_core.exceptions import MissingDependencyError
4140

@@ -132,19 +131,16 @@ def __post_init__(self) -> None:
132131
_assert_crt()
133132

134133

134+
class _CRTTimeoutError(Exception):
135+
"""Internal wrapper for CRT timeout errors."""
136+
137+
135138
class AWSCRTHTTPClient(http_aio_interfaces.HTTPClient):
136139
_HTTP_PORT = 80
137140
_HTTPS_PORT = 443
141+
_TIMEOUT_ERROR_NAMES = frozenset(["AWS_IO_SOCKET_TIMEOUT", "AWS_IO_SOCKET_CLOSED"])
138142

139-
def get_error_info(self, exception: Exception, **kwargs: Any) -> ClientErrorInfo:
140-
timeout_indicators = (
141-
"AWS_IO_SOCKET_TIMEOUT",
142-
"AWS_IO_SOCKET_CLOSED",
143-
)
144-
if isinstance(exception, AwsCrtError) and exception.name in timeout_indicators:
145-
return ClientErrorInfo(is_timeout_error=True)
146-
147-
return ClientErrorInfo(is_timeout_error=False)
143+
TIMEOUT_EXCEPTIONS = (_CRTTimeoutError,)
148144

149145
def __init__(
150146
self,
@@ -176,18 +172,23 @@ async def send(
176172
:param request: The request including destination URI, fields, payload.
177173
:param request_config: Configuration specific to this request.
178174
"""
179-
crt_request = self._marshal_request(request)
180-
connection = await self._get_connection(request.destination)
175+
try:
176+
crt_request = self._marshal_request(request)
177+
connection = await self._get_connection(request.destination)
181178

182-
# Convert body to async iterator for request_body_generator
183-
body_generator = self._create_body_generator(request.body)
179+
# Convert body to async iterator for request_body_generator
180+
body_generator = self._create_body_generator(request.body)
184181

185-
crt_stream = connection.request(
186-
crt_request,
187-
request_body_generator=body_generator,
188-
)
182+
crt_stream = connection.request(
183+
crt_request,
184+
request_body_generator=body_generator,
185+
)
189186

190-
return await self._await_response(crt_stream)
187+
return await self._await_response(crt_stream)
188+
except AwsCrtError as e:
189+
if e.name in self._TIMEOUT_ERROR_NAMES:
190+
raise _CRTTimeoutError() from e
191+
raise
191192

192193
async def _await_response(
193194
self, stream: "AIOHttpClientStreamUnified"

packages/smithy-http/tests/unit/aio/test_timeout_errors.py

Lines changed: 0 additions & 85 deletions
This file was deleted.

0 commit comments

Comments
 (0)