11# Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
22# SPDX-License-Identifier: Apache-2.0
33import datetime
4+ from asyncio import iscoroutinefunction
45from decimal import Decimal
56from dataclasses import dataclass , field
67from typing import ClassVar , Self , Any , Protocol
4041 TIMESTAMP ,
4142)
4243from smithy_core .aio .types import AsyncBytesReader
44+ from smithy_http .deserializers import HTTPResponseDeserializer
4345from smithy_json import JSONCodec
44-
46+ from smithy_http . aio import HTTPResponse as _HTTPResponse
4547from smithy_http import tuples_to_fields , Fields
4648from smithy_http .serializers import HTTPRequestSerializer , HTTPResponseSerializer
4749
@@ -388,6 +390,7 @@ def _consumer(schema: Schema, de: ShapeDeserializer) -> None:
388390 cls .SCHEMA .members ["boolean_list_member" ],
389391 lambda d : list_value .append (d .read_boolean (BOOLEAN )),
390392 )
393+ kwargs ["boolean_list_member" ] = list_value
391394 case 2 :
392395 kwargs ["integer_member" ] = de .read_integer (
393396 cls .SCHEMA .members ["integer_member" ]
@@ -564,7 +567,7 @@ class HTTPImplicitPayload:
564567 "target" : STRING ,
565568 "traits" : [HTTPHeaderTrait ("header" )],
566569 },
567- "payload_member" : {"index" : 0 , "target" : STRING },
570+ "payload_member" : {"index" : 1 , "target" : STRING },
568571 },
569572 )
570573
@@ -587,7 +590,11 @@ def deserialize(cls, deserializer: ShapeDeserializer) -> Self:
587590 def _consumer (schema : Schema , de : ShapeDeserializer ) -> None :
588591 match schema .expect_member_index ():
589592 case 0 :
590- kwargs ["payload" ] = de .read_string (cls .SCHEMA .members ["payload" ])
593+ kwargs ["header" ] = de .read_string (cls .SCHEMA .members ["header" ])
594+ case 1 :
595+ kwargs ["payload_member" ] = de .read_string (
596+ cls .SCHEMA .members ["payload_member" ]
597+ )
591598 case _:
592599 raise Exception (f"Unexpected schema: { schema } " )
593600
@@ -1281,6 +1288,21 @@ class HTTPMessageTestCase:
12811288]
12821289
12831290
1291+ EMPTY_PREFIX_HEADER_DESER_CASES : list [HTTPMessageTestCase ] = [
1292+ HTTPMessageTestCase (
1293+ HTTPEmptyPrefixHeaders (
1294+ string_member = "string" ,
1295+ string_map_member = {"foo" : "bar" , "baz" : "bam" , "string" : "string" },
1296+ ),
1297+ HTTPMessage (
1298+ fields = tuples_to_fields (
1299+ [("foo" , "bar" ), ("baz" , "bam" ), ("string" , "string" )]
1300+ ),
1301+ ),
1302+ ),
1303+ ]
1304+
1305+
12841306QUERY_CASES : list [HTTPMessageTestCase ] = [
12851307 HTTPMessageTestCase (
12861308 HTTPQuery (boolean_member = True ),
@@ -1529,6 +1551,9 @@ class HTTPMessageTestCase:
15291551 HTTPStructuredPayload (payload = HTTPStringPayload (payload = "foo" )),
15301552 HTTPMessage (body = BytesIO (b'{"payload":"foo"}' )),
15311553 ),
1554+ ]
1555+
1556+ ASYNC_STREAMING_PAYLOAD_CASES : list [HTTPMessageTestCase ] = [
15321557 HTTPMessageTestCase (
15331558 HTTPStreamingPayload (payload = AsyncBytesReader (b"\xde \xad \xbe \xef " )),
15341559 HTTPMessage (body = AsyncBytesReader (b"\xde \xad \xbe \xef " )),
@@ -1544,8 +1569,9 @@ class HTTPMessageTestCase:
15441569REQUEST_CASES .extend (PAYLOAD_CASES )
15451570
15461571REQUEST_SER_CASES : list [HTTPMessageTestCase ] = []
1547- REQUEST_CASES .extend (REQUEST_CASES )
1548- REQUEST_CASES .extend (EMPTY_PREFIX_HEADER_SER_CASES )
1572+ REQUEST_SER_CASES .extend (REQUEST_CASES )
1573+ REQUEST_SER_CASES .extend (EMPTY_PREFIX_HEADER_SER_CASES )
1574+ REQUEST_SER_CASES .extend (ASYNC_STREAMING_PAYLOAD_CASES )
15491575
15501576
15511577@pytest .mark .parametrize ("case" , REQUEST_SER_CASES )
@@ -1580,7 +1606,7 @@ async def test_serialize_http_request(case: HTTPMessageTestCase) -> None:
15801606RESPONSE_CASES .extend (PAYLOAD_CASES )
15811607
15821608RESPONSE_SER_CASES : list [HTTPMessageTestCase ] = []
1583- RESPONSE_CASES .extend (RESPONSE_CASES )
1609+ RESPONSE_SER_CASES .extend (RESPONSE_CASES )
15841610RESPONSE_SER_CASES .extend (EMPTY_PREFIX_HEADER_SER_CASES )
15851611
15861612
@@ -1602,3 +1628,40 @@ async def test_serialize_http_response(case: HTTPMessageTestCase) -> None:
16021628 expected_body_value = await AsyncBytesReader (case .request .body ).read ()
16031629 assert actual_body_value == expected_body_value
16041630 assert type (actual .body ) is type (case .request .body )
1631+
1632+
1633+ RESPONSE_DESER_CASES : list [HTTPMessageTestCase ] = []
1634+ RESPONSE_DESER_CASES .extend (RESPONSE_CASES )
1635+ RESPONSE_DESER_CASES .extend (EMPTY_PREFIX_HEADER_DESER_CASES )
1636+
1637+
1638+ # TODO: Move this to a separate file
1639+ @pytest .mark .parametrize ("case" , RESPONSE_DESER_CASES )
1640+ async def test_deserialize_http_response (case : HTTPMessageTestCase ) -> None :
1641+ body = case .request .body
1642+ if (read := getattr (body , "read" , None )) is not None and iscoroutinefunction (read ):
1643+ body = BytesIO (await read ())
1644+ deserializer = HTTPResponseDeserializer (
1645+ payload_codec = JSONCodec (),
1646+ http_trait = case .http_trait ,
1647+ response = _HTTPResponse (
1648+ body = case .request .body ,
1649+ status = case .request .status ,
1650+ fields = case .request .fields ,
1651+ ),
1652+ body = body ,
1653+ )
1654+ actual = type (case .shape ).deserialize (deserializer )
1655+ assert actual == case .shape
1656+
1657+
1658+ async def test_deserialize_http_response_with_async_stream () -> None :
1659+ stream = AsyncBytesReader (b"\xde \xad \xbe \xef " )
1660+
1661+ deserializer = HTTPResponseDeserializer (
1662+ payload_codec = JSONCodec (),
1663+ http_trait = HTTPTrait ({"method" : "POST" , "code" : 200 , "uri" : "/" }),
1664+ response = _HTTPResponse (body = stream , status = 200 , fields = Fields ()),
1665+ )
1666+ actual = HTTPStreamingPayload .deserialize (deserializer )
1667+ assert actual == HTTPStreamingPayload (stream )
0 commit comments