Aquí está mi conftest.py (algún código eliminado por brevedad)
from trip_planner import create_app, db as _db from trip_planner.models import User from test import TestConfig, test_instance_dir @pytest.fixture(scope='session', autouse=True) def app(session_mocker: pytest_mock.MockerFixture): static_folder = mkdtemp(prefix='static') _app = create_app(TestConfig(), instance_path=test_instance_dir, static_folder=static_folder) ctx = _app.app_context() ctx.push() session_mocker.patch('trip_planner.assets.manifest', new=defaultdict(str)) yield _app ctx.pop() os.rmdir(static_folder) @pytest.fixture(scope='session') def db(app): _db.create_all() seed_db(_db) yield _db _db.drop_all() def seed_db(db) -> User: sessionmaker = db.create_session({'autocommit': False}) session = sessionmaker() user = User(username='username', password_digest=bcrypt.hash('password')) session.add(user) session.commit() session.close() return user @pytest.fixture(scope='function') def db_session(db): session = db.create_scoped_session(options=dict( autocommit=False, autoflush=False )) db.session = session with session.begin_nested(): yield session session.rollback() session.remove() @pytest.fixture(scope='function') def app_client(app): with app.test_client() as c: yield c @pytest.fixture(scope='function') def session_user(db_session, app_client) -> int: user_id, = db_session.query(User.id).filter_by(username='username').one() with app_client.session_transaction() as sess: sess['user_id'] = user_id return user_id Cuando pasan mis pruebas, pytest se cuelga. Solo puedo detenerlo con killall . La inspección de la base de datos de prueba revela que, de hecho, las relaciones no se eliminaron.
¿Cómo soluciono esto?
Aparentemente, es un problema bien conocido con PostgreSQL específicamente, aquí está la discusión.
La forma en que lo resolví fue agregando _db.close_all_sessions() antes de eliminar todas las tablas:
@pytest.fixture(scope='session') def db(app): _db.create_all() seed_db(_db) yield _db _db.close_all_sessions() _db.drop_all()Otra razón por la que podría haber sido el caso antes, no estoy seguro. Pero vale la pena verificar si revisa pg_stat_activity y ve que sus consultas dependen de la obtención de bloqueos de aviso.
Aparentemente, los bloqueos de aviso pueden ser de nivel de sesión o de transacción en PostgreSQL. Un bloqueo de aviso a nivel de sesión no se libera al final de la transacción, solo al desconectarse. Puede hacer que las sesiones superpuestas se cuelguen mientras una intenta revertir todo y la otra intenta tomar un bloqueo de aviso.
Se obtiene un bloqueo de aviso a nivel de sesión a través de las funciones pg_advisory_lock y un bloqueo de aviso a nivel de transacción se obtiene a través de las funciones pg_advisory_xact_lock .