0.69 introduces a RuntimeError: Task <...>got Future <Future pending> attached to a different loop
See original GitHub issueFirst Check
- I added a very descriptive title to this issue.
- I used the GitHub search to find a similar issue and didn’t find it.
- I searched the FastAPI documentation, with the integrated search.
- I already searched in Google “How to X in FastAPI” and didn’t find any information.
- I already read and followed all the tutorial in the docs and didn’t find an answer.
- I already checked if it is not related to FastAPI but to Pydantic.
- I already checked if it is not related to FastAPI but to Swagger UI.
- I already checked if it is not related to FastAPI but to ReDoc.
Commit to Help
- I commit to help with one of those options 👆
Example Code
Create a venv with the following versions:
fastapi==0.70.0
tortoise-orm==0.17.8
pytest==6.2.5
save this code as main.py
(name is important!)
from typing import Dict
import pytest
from fastapi import FastAPI
from fastapi import status
from fastapi.testclient import TestClient
from tortoise import Model
from tortoise import Tortoise
from tortoise.fields import CharField, ManyToManyRelation, ManyToManyField
class DbObj(Model):
name: str = CharField(max_length=255, pk=True)
my_rels1: ManyToManyRelation['DbObjRelation1']
my_rels2: ManyToManyRelation['DbObjRelation2']
class DbObjRelation1(Model):
name: str = CharField(max_length=255, pk=True)
my_objs: ManyToManyRelation['DbObj'] = ManyToManyField('models.DbObj', related_name='my_rels1')
class DbObjRelation2(Model):
name: str = CharField(max_length=255, pk=True)
my_objs: ManyToManyRelation['DbObj'] = ManyToManyField('models.DbObj', related_name='my_rels2')
app = FastAPI(title='Server')
@app.get(
path="/obj",
response_model=Dict[str, str],
status_code=status.HTTP_200_OK,
)
async def obj_get():
ct = await DbObj.all().prefetch_related('my_rels1', 'my_rels2')
ret = {}
for obj in ct:
ret[obj.name] = ', '.join(list(r.name for r in obj.my_rels1))
return ret
@app.put(
path="/obj/{name}",
response_model=Dict[str, str],
status_code=status.HTTP_200_OK,
)
async def obj_create(name: str):
obj = await DbObj.create(name=name)
rel = await DbObjRelation1.create(name=f'{name}_rel')
await obj.my_rels1.add(rel)
return None
test_client = TestClient(app)
@pytest.fixture(scope="function", autouse=True)
@pytest.mark.asyncio
async def db(monkeypatch):
await Tortoise.init(db_url='sqlite://:memory:', modules={'models': ['main']})
await Tortoise.generate_schemas()
yield
await Tortoise.close_connections()
def test_read_main():
# create one object
response = test_client.put("/obj/name1")
assert response.status_code == 200
# read it back
response = test_client.get("/obj")
assert response.status_code == 200
assert response.json() == {'name1': 'name1_rel'}
Description
FastAPI 0.68.2 runs without issues. From FastAPI 0.69.0 on tests fail:
run
pytest main.py
results in
Testing started at 14:43 ...
Launching pytest with arguments C:/MyTestVenv/src/main.py --no-header --no-summary -q in C:/MyTestVenv/src
============================= test session starts =============================
collecting ... collected 1 item
main.py::test_read_main FAILED [100%]
main.py:69 (test_read_main)
def test_read_main():
# create one object
response = test_client.put("/obj/name1")
assert response.status_code == 200
# read it back
> response = test_client.get("/obj")
main.py:76:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
..\venv\lib\site-packages\requests\sessions.py:555: in get
return self.request('GET', url, **kwargs)
..\venv\lib\site-packages\starlette\testclient.py:468: in request
return super().request(
..\venv\lib\site-packages\requests\sessions.py:542: in request
resp = self.send(prep, **send_kwargs)
..\venv\lib\site-packages\requests\sessions.py:655: in send
r = adapter.send(request, **kwargs)
..\venv\lib\site-packages\starlette\testclient.py:266: in send
raise exc
..\venv\lib\site-packages\starlette\testclient.py:263: in send
portal.call(self.app, scope, receive, send)
..\venv\lib\site-packages\anyio\from_thread.py:230: in call
return cast(T_Retval, self.start_task_soon(func, *args).result())
C:\Program Files\Python38\lib\concurrent\futures\_base.py:439: in result
return self.__get_result()
C:\Program Files\Python38\lib\concurrent\futures\_base.py:388: in __get_result
raise self._exception
..\venv\lib\site-packages\anyio\from_thread.py:177: in _call_func
retval = await retval
..\venv\lib\site-packages\fastapi\applications.py:208: in __call__
await super().__call__(scope, receive, send)
..\venv\lib\site-packages\starlette\applications.py:112: in __call__
await self.middleware_stack(scope, receive, send)
..\venv\lib\site-packages\starlette\middleware\errors.py:181: in __call__
raise exc
..\venv\lib\site-packages\starlette\middleware\errors.py:159: in __call__
await self.app(scope, receive, _send)
..\venv\lib\site-packages\starlette\exceptions.py:82: in __call__
raise exc
..\venv\lib\site-packages\starlette\exceptions.py:71: in __call__
await self.app(scope, receive, sender)
..\venv\lib\site-packages\starlette\routing.py:656: in __call__
await route.handle(scope, receive, send)
..\venv\lib\site-packages\starlette\routing.py:259: in handle
await self.app(scope, receive, send)
..\venv\lib\site-packages\starlette\routing.py:61: in app
response = await func(request)
..\venv\lib\site-packages\fastapi\routing.py:226: in app
raw_response = await run_endpoint_function(
..\venv\lib\site-packages\fastapi\routing.py:159: in run_endpoint_function
return await dependant.call(**values)
main.py:37: in obj_get
ct = await DbObj.all().prefetch_related('my_rels1', 'my_rels2')
..\venv\lib\site-packages\tortoise\queryset.py:966: in _execute
instance_list = await self._db.executor_class(
..\venv\lib\site-packages\tortoise\backends\base\executor.py:176: in execute_select
await self._execute_prefetch_queries(instance_list)
..\venv\lib\site-packages\tortoise\backends\base\executor.py:567: in _execute_prefetch_queries
await asyncio.gather(*prefetch_tasks)
..\venv\lib\site-packages\tortoise\backends\base\executor.py:555: in _do_prefetch
return await self._prefetch_m2m_relation(instance_id_list, field, related_query)
..\venv\lib\site-packages\tortoise\backends\base\executor.py:470: in _prefetch_m2m_relation
_, raw_results = await self.db.execute_query(query.get_sql())
..\venv\lib\site-packages\tortoise\backends\sqlite\client.py:30: in translate_exceptions_
return await func(self, query, *args)
..\venv\lib\site-packages\tortoise\backends\sqlite\client.py:133: in execute_query
async with self.acquire_connection() as connection:
..\venv\lib\site-packages\tortoise\backends\base\client.py:213: in __aenter__
await self.lock.acquire()
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
self = <asyncio.locks.Lock object at 0x0000023238D27F10 [unlocked]>
async def acquire(self):
"""Acquire a lock.
This method blocks until the lock is unlocked, then sets it to
locked and returns True.
"""
if (not self._locked and (self._waiters is None or
all(w.cancelled() for w in self._waiters))):
self._locked = True
return True
if self._waiters is None:
self._waiters = collections.deque()
fut = self._loop.create_future()
self._waiters.append(fut)
# Finally block should be called before the CancelledError
# handling as we don't want CancelledError to call
# _wake_up_first() and attempt to wake up itself.
try:
try:
> await fut
E RuntimeError: Task <Task pending name='Task-11' coro=<BaseExecutor._do_prefetch() running at C:\MyTestVenv\venv\lib\site-packages\tortoise\backends\base\executor.py:555> cb=[gather.<locals>._done_callback() at C:\Program Files\Python38\lib\asyncio\tasks.py:769]> got Future <Future pending> attached to a different loop
C:\Program Files\Python38\lib\asyncio\locks.py:203: RuntimeError
============================== 1 failed in 0.63s ==============================
Process finished with exit code 1
Operating System
Windows
Operating System Details
No response
FastAPI Version
0.70.0
Python Version
Python 3.8.8
Additional Context
No response
Issue Analytics
- State:
- Created 2 years ago
- Comments:9 (1 by maintainers)
Top Results From Across the Web
Task got Future <Future pending> attached to a different loop ...
This method returns the event loop for the current thread, which in your code, is the main thread. Telethon then remembers and uses...
Read more >tiangolo/fastapi - Gitter
I want to run a background task but one that's not scheduled by a ... My error is always "got Future <Future pending>...
Read more >Release Notes - FastAPI
You can start with Python Types Intro, it explains what changes between different Python versions, in Python 3.9 and in Python 3.10. All...
Read more >Apache Tomcat 9 (9.0.70) - Changelog
To aid future additions of new functionality, rather than throw an ... Update ImportHandler optimisation for new classes introduced in Java 19. (markt) ......
Read more >Data Structures and Algorithm Analysis in C++ - UOITC
introduced in C++11. r. Chapter 8 uses the new union/find analysis by Seidel and Sharir and shows the. O( M α(M, N) )...
Read more >Top Related Medium Post
No results found
Top Related StackOverflow Question
No results found
Troubleshoot Live Code
Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start FreeTop Related Reddit Thread
No results found
Top Related Hackernoon Post
No results found
Top Related Tweet
No results found
Top Related Dev.to Post
No results found
Top Related Hashnode Post
No results found
Top GitHub Comments
No, but those who are async use the
AsyncTestClient
. I am using@pytest.mark.asyncio
for these functions but I guess.anyio
would be more correct. See the first example from the link for the import.@spacemanspiff2007 so, all your tests are
async
? Do you use pytest for testing? If so, are you doingpytest.mark.anyio
to all your tests?From where do you import
AsyncTestClient
? Or is it just a renaming ofhttpx.AsyncClient
? Thanks