Issue
Using FastAPI : 0.101.1
I run this test_read_aynsc
and it pass.
# app.py
from fastapi import FastAPI
app = FastAPI()
app.get("/")
def read_root():
return {"Hello": "World"}
# conftest.py
import pytest
from typing import Generator
from fastapi.testclient import TestClient
from server import app
@pytest.fixture(scope="session")
def client() -> Generator:
with TestClient(app) as c:
yield c
# test_root.py
def test_read_aynsc(client):
response = client.get("/item")
However, executing this test in DEBUG mode (in pycharm) will cause an error. Here is the Traceback :
test setup failed
cls = <class 'anyio._backends._asyncio.AsyncIOBackend'>
func = <function start_blocking_portal.<locals>.run_portal at 0x1555c51b0>
args = (), kwargs = {}, options = {}
@classmethod
def run(
cls,
func: Callable[[Unpack[PosArgsT]], Awaitable[T_Retval]],
args: tuple[Unpack[PosArgsT]],
kwargs: dict[str, Any],
options: dict[str, Any],
) -> T_Retval:
@wraps(func)
async def wrapper() -> T_Retval:
task = cast(asyncio.Task, current_task())
task.set_name(get_callable_name(func))
_task_states[task] = TaskState(None, None)
try:
return await func(*args)
finally:
del _task_states[task]
debug = options.get("debug", False)
loop_factory = options.get("loop_factory", None)
if loop_factory is None and options.get("use_uvloop", False):
import uvloop
loop_factory = uvloop.new_event_loop
with Runner(debug=debug, loop_factory=loop_factory) as runner:
> return runner.run(wrapper())
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:1991:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:193: in run
return self._loop.run_until_complete(task)
../../../Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-0/233.13763.11/PyCharm.app/Contents/plugins/python/helpers-pro/pydevd_asyncio/pydevd_nest_asyncio.py:202: in run_until_complete
self._run_once()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_UnixSelectorEventLoop running=False closed=True debug=False>
def _run_once(self):
"""
Simplified re-implementation of asyncio's _run_once that
runs handles as they become ready.
"""
ready = self._ready
scheduled = self._scheduled
while scheduled and scheduled[0]._cancelled:
heappop(scheduled)
timeout = (
0 if ready or self._stopping
else min(max(
scheduled[0]._when - self.time(), 0), 86400) if scheduled
else None)
event_list = self._selector.select(timeout)
self._process_events(event_list)
end_time = self.time() + self._clock_resolution
while scheduled and scheduled[0]._when < end_time:
handle = heappop(scheduled)
ready.append(handle)
> if self._compute_internal_coro:
E AttributeError: '_UnixSelectorEventLoop' object has no attribute '_compute_internal_coro'
../../../Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-0/233.13763.11/PyCharm.app/Contents/plugins/python/helpers-pro/pydevd_asyncio/pydevd_nest_asyncio.py:236: AttributeError
During handling of the above exception, another exception occurred:
@pytest.fixture(scope="session")
def client() -> Generator:
> with TestClient(app) as c:
tests/fixtures/common/http_client_app.py:10:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/starlette/testclient.py:730: in __enter__
self.portal = portal = stack.enter_context(
../../../.pyenv/versions/3.10.12/lib/python3.10/contextlib.py:492: in enter_context
result = _cm_type.__enter__(cm)
../../../.pyenv/versions/3.10.12/lib/python3.10/contextlib.py:135: in __enter__
return next(self.gen)
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/from_thread.py:454: in start_blocking_portal
run_future.result()
../../../.pyenv/versions/3.10.12/lib/python3.10/concurrent/futures/_base.py:451: in result
return self.__get_result()
../../../.pyenv/versions/3.10.12/lib/python3.10/concurrent/futures/_base.py:403: in __get_result
raise self._exception
../../../.pyenv/versions/3.10.12/lib/python3.10/concurrent/futures/thread.py:58: in run
result = self.fn(*self.args, **self.kwargs)
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_core/_eventloop.py:73: in run
return async_backend.run(func, args, {}, backend_options)
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:1990: in run
with Runner(debug=debug, loop_factory=loop_factory) as runner:
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:133: in __exit__
self.close()
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:141: in close
_cancel_all_tasks(loop)
../../../Library/Caches/pypoetry/virtualenvs/kms-backend-F9vGicV3-py3.10/lib/python3.10/site-packages/anyio/_backends/_asyncio.py:243: in _cancel_all_tasks
loop.run_until_complete(tasks.gather(*to_cancel, return_exceptions=True))
../../../Library/Application Support/JetBrains/Toolbox/apps/PyCharm-P/ch-0/233.13763.11/PyCharm.app/Contents/plugins/python/helpers-pro/pydevd_asyncio/pydevd_nest_asyncio.py:202: in run_until_complete
self._run_once()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <_UnixSelectorEventLoop running=False closed=True debug=False>
def _run_once(self):
"""
Simplified re-implementation of asyncio's _run_once that
runs handles as they become ready.
"""
ready = self._ready
scheduled = self._scheduled
while scheduled and scheduled[0]._cancelled:
heappop(scheduled)
timeout = (
0 if ready or self._stopping
else min(max(
scheduled[0]._when - self.time(), 0), 86400) if scheduled
else None)
event_list = self._selector.select(timeout)
self._process_events(event_list)
end_time = self.time() + self._clock_resolution
while scheduled and scheduled[0]._when < end_time:
handle = heappop(scheduled)
ready.append(handle)
> if self._compute_internal_coro:
E AttributeError: '_UnixSelectorEventLoop' object has no attribute '_compute_internal_coro'
I am not sure to understand what causes the error
Since I can see the _UnixSelectorEventLoop
, I need to precise that my operating system is MacOS M1.
Solution
To support async debugging, PyCharm patches a bunch of asyncio APIs with custom wrapped functions. Notably, it patches asyncio.new_event_loop()
in ~/Applications/PyCharm Professional Edition.app/Contents/plugins/python/helpers-pro/pydevd_asyncio/pydevd_nest_asyncio.py:169
.
Starlette uses anyio, with the asyncio backend by default. Anyio is eventually gonna try to get its event loop from asyncio.events.new_event_loop()
, which is unpatched. Subsequent calls to patched asyncio APIs are gonna throw errors because they assume a patched event loop.
Until it's fixed properly, you can resolve this issue by forcing anyio to use the patched new_event_loop
with
TestClient(app, backend_options={'loop_factory': asyncio.new_event_loop})
Answered By - ahoff
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.