aiohttp mock only works when using request methods as context managers, but not when awaited
sarayourfriend opened this issue · 3 comments
Hello, thank you for the lovely project! It makes HTTP mocking really pleasant to work with.
I noticed a small issue with the implementation of the aiohttp mock: it appears to only work when using the request methods as context managers, but not when their results are awaited.
This gist has example code to show this in a pytest unit test: https://gist.github.com/sarayourfriend/44a33e7397849939156247457d8bb773
Here is the full output of running the tests:
➜ aiohttp-example pdm run pytest
/home/sara/.local/lib/python3.10/site-packages/requests/__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.12) or chardet (5.0.0)/charset_normalizer (2.0.12) doesn't match a supported version!
warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "
=================================== test session starts ===================================
platform linux -- Python 3.10.8, pytest-7.2.0, pluggy-1.0.0
rootdir: /home/sara/projects/aiohttp-example
plugins: anyio-3.6.2, asyncio-0.20.2
asyncio: mode=strict
collected 2 items
main_test.py .F [100%]
======================================== FAILURES =========================================
_________________________________ test_make_request_await _________________________________
async def test_make_request_await():
pook.head(URL).reply(200)
pook.on()
> res = await make_request_await()
main_test.py:36:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
main_test.py:19: in make_request_await
response = await session.head(URL)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <aiohttp.client._RequestContextManager object at 0x7f7cb9dfc9d0>
def __await__(self) -> Generator[Any, None, _RetType]:
> ret = self._coro.__await__()
E AttributeError: 'generator' object has no attribute '__await__'. Did you mean: '__init__'?
.venv/lib/python3.10/site-packages/aiohttp/client.py:1134: AttributeError
==================================== warnings summary =====================================
.venv/lib/python3.10/site-packages/pook/interceptors/aiohttp.py:48
/home/sara/projects/aiohttp-example/.venv/lib/python3.10/site-packages/pook/interceptors/aiohttp.py:48: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def read(self, n=-1):
.venv/lib/python3.10/site-packages/pook/interceptors/aiohttp.py:80
/home/sara/projects/aiohttp-example/.venv/lib/python3.10/site-packages/pook/interceptors/aiohttp.py:80: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def _on_request(self, _request, session, method, url,
main_test.py::test_make_request_ctx
main_test.py::test_make_request_await
/home/sara/projects/aiohttp-example/.venv/lib/python3.10/site-packages/pook/interceptors/aiohttp.py:153: DeprecationWarning: "@coroutine" decorator is deprecated since Python 3.8, use "async def" instead
def handler(session, method, url, data=None, headers=None, **kw):
-- Docs: https://docs.pytest.org/en/stable/how-to/capture-warnings.html
================================= short test summary info =================================
FAILED main_test.py::test_make_request_await - AttributeError: 'generator' object has no attribute '__await__'. Did you mean: '__init...
========================= 1 failed, 1 passed, 4 warnings in 0.09s =========================
As you can see, test_make_request_await
fails whereas the other test case which uses the request method as a context manger passes fine.
It looks like this comes down to an issue with the return value of the _request
mock that pook is applying: it must be a coroutine but is currently a generator. I'm not sure exactly why this is the case, because the mock handler is wrapped in @asyncio.coroutine
.
I've managed to patch this locally by removing the usage of the asyncio.coroutine
decorator and replacing the methods with regular async def
methods. I'll open a PR with these changes later this week.
I was reading through the implementation and realised it is backwards compatible even with 2.7. I'll try and see if it is fixable using asyncio.coroutine
in order to maintain that backwards compatibility.
Hello! 2.7 compatibility is not an issue, the problem is 3.4 which does not support async/await syntax operators, but I'm willing to deprecate 3.4 at this point and only support 3.5+ versions, so feel free to send a PR.
Right on! I'll have a PR for you within the next couple of days.