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
相关产品推荐
相关产品推荐

