Cannot perform operation: another operation is in progress
- GINO version: 1.0.1
- Python version: 3.8
- asyncpg version: 0.21.0
- aiocontextvars version: 0.2.2
- PostgreSQL version: 10.14
Description
My task is create some database record (via GINO Model.create()) before running test (typical pytest.fixture usage), and drop everything after.
What I Did
conftest.py
import pytest
from fastapi.testclient import TestClient
from alembic.config import main as alembic_main
from settings import settings
settings.DATABASE_NAME = 'test_db_name'
from main import app_init
@pytest.fixture
def client():
alembic_main(["--raiseerr", "upgrade", "head"])
with TestClient(app_init()) as client:
yield client
alembic_main(["--raiseerr", "downgrade", "base"])
test.py
import pytest
from models import SpecialModel
@pytest.fixture
async def special_model():
special_model = await SpecialModel.create(
internal_name='internal_name',
comment='comment',
is_active=True,
title="Title",
text="Text"
)
yield special_model
def test_get_all_special_models(client, special_model):
response = client.get("api/get_all_models")
data = response.json()
assert data["success"] is True
assert len(data["result"]) == 1
What I got:
test setup failed
@pytest.fixture
async def special_model():
> special_model = await SpecialModel.create(
internal_name='internal_name',
comment='comment',
is_active=True,
title="Title",
text="Text"
)
tests/test.py:8:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/crud.py:444: in _create_without_instance
return await cls(**values)._create(bind=bind, timeout=timeout)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/crud.py:477: in _create
row = await bind.first(q)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:748: in first
return await conn.first(clause, *multiparams, **params)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:147: in __aexit__
await conn.release()
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:279: in release
await dbapi_conn.release(True)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:47: in release
return await self._release()
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/engine.py:83: in _release
await self._pool.release(conn)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/gino/dialects/asyncpg.py:232: in release
await self._pool.release(conn)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:654: in release
return await asyncio.shield(ch.release(timeout))
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:216: in release
raise ex
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/pool.py:206: in release
await self._con.reset(timeout=budget)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/connection.py:1137: in reset
await self.execute(reset_query, timeout=timeout)
../../.virtualenvs/deeplink-offer-service/lib/python3.8/site-packages/asyncpg/connection.py:295: in execute
return await self._protocol.query(query, timeout)
asyncpg/protocol/protocol.pyx:301: in query
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress
@ErhoSen I faced the same problem, solution was to use a separate db connection:
@pytest.fixture
async def special_model():
async with db.acquire(): # use seperate db connection
special_model = await SpecialModel.create(
internal_name='internal_name',
comment='comment',
is_active=True,
title="Title",
text="Text"
)
yield special_model
This isn't an issue with gino it's an asyncpg issue. Basically, asyncpg can't make two concurrent queries using the same db connection.
Thanks! This deserves a page in the docs.
I have the same exception asyncpg.exceptions._base.InterfaceError: cannot perform operation: another operation is in progress when I run pytest.
Any idea what I did wrong? I would appreciate any help. Thanks in advance.
requirements.txt
fastapi==0.70.0
gino==1.0.1
pytest==6.2.5
pytest-asyncio==0.16.0
requests==2.26.0
test_code.py
import os
from typing import List
import pytest
from gino import Gino
from fastapi import APIRouter
from pydantic import BaseModel
from fastapi import FastAPI
from starlette.testclient import TestClient
router = APIRouter()
db = Gino()
async def init_db():
await db.set_bind(os.environ['DATABASE_URL'])
await db.gino.create_all()
class UserModel(db.Model):
__tablename__ = 'user'
id = db.Column(db.Integer(), primary_key=True)
name = db.Column(db.Unicode())
email = db.Column(db.Unicode(), unique=True, index=True)
password_hash = db.Column(db.Unicode())
class UserSchema(BaseModel):
id: int = 0
name: str
email: str
password: str
class UserListSchema(BaseModel):
objects: List[UserSchema]
@router.get("/users/", response_model=UserListSchema)
async def get_users():
async with db.acquire():
users = await UserModel.query.limit(200).gino.all()
return UserListSchema.parse_obj({
'objects': [x.to_dict() for x in users]
})
def get_app():
print('INIT APP')
app = FastAPI(title="GINO FastAPI Demo")
app.include_router(router, prefix='/API/v1')
@app.on_event("startup")
async def startup_event():
print('Initialising DB')
await init_db()
print('DB was initialised')
return app
@pytest.fixture
def client():
with TestClient(get_app()) as client:
yield client
@pytest.fixture
@pytest.mark.anyio
async def user(client):
print('[-------->')
# await init_db()
# async with db.acquire():
user = await UserModel.create(email='[email protected]')
# async with db.acquire():
users = await UserModel.query.limit(200).gino.all()
print('.....=', user)
print('....._', users)
yield user
def test_users(user, client):
response = client.get(
"/API/v1/users",
headers={},
)
print('=====', user, response.text)
assert response.status_code == 200
assert response.json() == {}