You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Pytest清理阶段SQLite文件被占用引发PermissionError问题求助

解决Pytest清理阶段SQLite文件被占用的问题

问题核心原因

你遇到的PermissionError是因为SQLAlchemy的引擎连接池仍持有数据库文件的活跃连接,即使关闭了scoped_session,引擎本身的连接池还会保留打开的连接,Windows系统下文件锁定机制更严格,导致无法删除文件。另外,模块级别的引擎初始化会导致全局连接被持久持有,测试时无法彻底释放。

具体解决方案

1. 重构数据库工厂代码,延迟引擎初始化

将engine和db_session的初始化从模块级别移到init_db函数内,避免全局持久化连接:

# ./src/database/database_factory.py
from flask import current_app
from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker

# 先声明全局变量,在init_db中初始化
engine = None
db_session = None

def init_db():
    global engine, db_session
    from database.models import Base, Table1, Table2, Table3, Table4
    
    # 从当前应用上下文获取配置,动态创建引擎
    engine = create_engine(current_app.config['SQLALCHEMY_DATABASE_URI'])
    db_session = scoped_session(sessionmaker(autocommit=False,
                                            autoflush=False,
                                            bind=engine))
    
    Base.metadata.create_all(bind=engine,
                             tables=[Table1.__table__, Table2.__table__, Table3.__table__, Table4.__table__])


@current_app.teardown_appcontext
def shutdown_session(exception=None):
    if db_session:
        db_session.remove()

2. 修改Pytest Fixture,彻底释放连接并指定正确路径

在fixture的清理阶段,先销毁引擎连接池,再删除数据库文件,同时显式指定测试用的instance路径,避免路径混乱:

# ./tests/unit/conftest.py
import os
import pytest
from app_factory import create_app
from database.database_factory import engine, db_session

@pytest.fixture()
def app():
    # 显式构造测试用的instance绝对路径,确保指向tests/instance
    test_instance_dir = os.path.abspath(os.path.join(os.path.dirname(__file__), "../instance"))
    app = create_app()
    # 覆盖应用的instance路径,强制使用测试目录
    app.instance_path = test_instance_dir
    
    yield app
    
    # 清理顺序:先移除会话,再销毁引擎连接池(关键步骤)
    if db_session:
        db_session.remove()
    if engine:
        engine.dispose()
    
    # 构造正确的数据库文件路径
    db_file_path = os.path.join(test_instance_dir, "test_db.sqlite")
    if os.path.exists(db_file_path):
        os.remove(db_file_path)

3. 补充说明

  • 关于清理阶段能导入db_session的问题:因为模块在create_app调用init_db时已经被导入,模块级变量会被保留,即使没有应用上下文也能导入(只是平时在上下文外访问current_app会报错,但这里仅导入变量不会触发错误)。
  • 显式指定测试instance路径:避免因Pytest运行时工作目录变化,导致误删src目录下的数据库文件。

内容的提问来源于stack exchange,提问作者novice

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 14:46:03