Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support moto by allowing non-awaitable content #1007

Closed
wants to merge 3 commits into from
Closed
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 CHANGES.rst
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
Changes
-------
2.5.1 (2023-04-05)
^^^^^^^^^^^^^^^^^^
* Add support for moto by allowing non-awaitable content

2.5.0 (2023-03-06)
^^^^^^^^^^^^^^^^^^
* bump botocore to 1.29.76 (thanks @jakob-keller #999)
Expand Down
6 changes: 4 additions & 2 deletions aiobotocore/endpoint.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@
from aiobotocore.httpsession import AIOHTTPSession
from aiobotocore.response import StreamingBody

from ._helpers import resolve_awaitable


async def convert_to_response_dict(http_response, operation_model):
"""Convert an HTTP response object to a request dict.
Expand Down Expand Up @@ -53,14 +55,14 @@ async def convert_to_response_dict(http_response, operation_model):
},
}
if response_dict['status_code'] >= 300:
response_dict['body'] = await http_response.content
response_dict['body'] = await resolve_awaitable(http_response.content)
elif operation_model.has_event_stream_output:
response_dict['body'] = http_response.raw
elif operation_model.has_streaming_output:
length = response_dict['headers'].get('content-length')
response_dict['body'] = StreamingBody(http_response.raw, length)
else:
response_dict['body'] = await http_response.content
response_dict['body'] = await resolve_awaitable(http_response.content)
return response_dict


Expand Down
89 changes: 89 additions & 0 deletions tests/test_response.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
import io
from unittest.mock import patch

import pytest
from botocore.awsrequest import AWSResponse
from botocore.exceptions import IncompleteReadError
from moto.core.botocore_stubber import MockRawResponse

from aiobotocore import response
from aiobotocore.endpoint import convert_to_response_dict


# https://github.com/boto/botocore/blob/develop/tests/unit/test_response.py
Expand Down Expand Up @@ -187,3 +191,88 @@ async def test_streaming_line_empty_body():
content_length=0,
)
await assert_lines(stream.iter_lines(), [])


@pytest.mark.moto
@pytest.mark.asyncio
async def test_convert_to_response_dict_non_awaitable_ok():
class MockOperationalModel:
def name(self):
return 'test'

@property
def has_streaming_output(self):
return False

@property
def has_event_stream_output(self):
return False

url = 'https://testbucket.s3.amazonaws.com/'
status = 200
headers = {
'x-amzn-requestid': '0n32brAiyTp2t9rdLgFtTmvlh4ZoPpIf62mizOK0W9Nt9lZr5XRL'
}
body = (
b'<CreateBucketResponse xmlns="http://s3.amazonaws.com/doc/2006-03-01">'
b'<CreateBucketResponse><Bucket>testbucket</Bucket>'
b'</CreateBucketResponse></CreateBucketResponse>'
)

raw = MockRawResponse(body)
encoded_headers = [
(
str(header).encode(encoding='utf-8'),
str(value).encode(encoding='utf-8'),
)
for header, value in headers.items()
]
raw.raw_headers = encoded_headers

operational_model = MockOperationalModel()
response = AWSResponse(url, status, headers, raw)

response = await convert_to_response_dict(response, operational_model)
assert response['body'] == body


@patch('aiobotocore._helpers.inspect.isawaitable', return_value=True)
@pytest.mark.moto
@pytest.mark.asyncio
async def test_convert_to_response_dict_non_awaitable_fail(mock_awaitable):
class MockOperationalModel:
def name(self):
return 'test'

@property
def has_streaming_output(self):
return False

@property
def has_event_stream_output(self):
return False

url = 'https://testbucket.s3.amazonaws.com/'
status = 200
headers = {
'x-amzn-requestid': '0n32brAiyTp2t9rdLgFtTmvlh4ZoPpIf62mizOK0W9Nt9lZr5XRL'
}
body = (
b'<CreateBucketResponse xmlns="http://s3.amazonaws.com/doc/2006-03-01">'
b'<CreateBucketResponse><Bucket>testbucket</Bucket>'
b'</CreateBucketResponse></CreateBucketResponse>'
)
raw = MockRawResponse(body)
encoded_headers = [
(
str(header).encode(encoding='utf-8'),
str(value).encode(encoding='utf-8'),
)
for header, value in headers.items()
]
raw.raw_headers = encoded_headers
operational_model = MockOperationalModel()
response = AWSResponse(url, status, headers, raw)
with pytest.raises(TypeError) as e:
await convert_to_response_dict(response, operational_model)
assert "can't be used in 'await' expression" in str(e)