Support for async?
See original GitHub issueThe problem
Coming from Django where we used Factory Boy really a lot to a new, async stack to fully support GraphQL with subscriptions which are really cool (uvicorn + Starlette + Ariadne) we also switched to async ORM (not really an ORM) named GINO. It is based on SQLAlchemy Core and works pretty robust. However, I am struggling to adapt Factory Boy to use GINO models.
Proposed solution
At first glance I thought that I need to implement _create()
method in my factory model but the problem is that the create()
method for GINO model is a coroutine and can’t be called from a synchronous code. I tried to experiment with asyncio._get_running_loop()
but I am really new to async stuff and my attempt failed.
Extra notes
I am using pytest with pytest-asyncio plugin to run tests with async code which works pretty well including working with DB. For that I have this in my conftest.py:
@pytest.fixture(scope="session")
def event_loop():
"""
This is to make the asyncio event loop shared for the whole test session, otherwise
it will be recreated for each test which will prevent using the test_db fixture.
"""
loop = asyncio.get_event_loop()
yield loop
loop.close()
@pytest.fixture(autouse=True, scope="session")
async def test_db(request):
"""
Here is some DB preparation code like (re)creating DB itself, making sure we have all
necessary rights etc.
"""
await db.gino.create_all() # this is to bind the GINO engine to DB
yield # passing context back to the tests
await db.pop_bind().close() # unbinding engine and performing other teardown later
I really miss Factory Boy and hope there is an easy solution to start my factories again. I also created an issue for GINO here https://github.com/fantix/gino/issues/608 but decided to open one here too as I think Factory Boy developed a much wider community and I have better chances that someone has the same problem as I do. Thanks all!
Issue Analytics
- State:
- Created 4 years ago
- Reactions:6
- Comments:7 (1 by maintainers)
Top GitHub Comments
Sometimes you just need to lay down your thoughts to get the proper idea. Also, the fresh mind helps (I was doing my experiments at 4am yesterday:)
I am not sure this is correct way to proceed and whether there are some unforeseen consequences that will shot me in the knee later but here’s what I did:
Then in my test I do
and get my new shiny user object created properly in DB! So far I am very happy with the result.
If more wise and experienced developers won’t see any issues with this approach I think it may worse adding something like this to the recipes section as async stack is getting more and more popular. I am leaving this issue open for now as I hope there will be some comments and/or advice. If not, it is absolutely fine to close it.
Thanks, that really helped me. I extended your version to support more features.
In the following example:
The
_create
function of UserFactory is called to create the Article Author, this returns a Task. Then the_create_
function of Category is called, with the User creation Task in its kwarg, which is awaited. The category model creation can use the User instance. Finally the_create
function of Article is called, also with the User creation Task. It is awaited again. The user instance is used in the article creation.