权限错误:[WinError 32] 进程无法访问文件,因为它正在被另一个进程使用:'./instance/test_db.sqlite
我在处理pytest的上下文销毁时遇到了一些麻烦。我有一个Flask应用,它会在我的实例目录中创建一个sqlite3数据库,结构如下:
# ./src/app_factory/__init__.py
def create_app():
app = Flask(__name__, instance_path=f'{os.path.abspath("instance")}', instance_relative_config=True, template_folder='templates')
# some code here
with app.app_context():
from database.database_factory import init_db
init_db()
# some other code here
return app
init_db()
函数是这样定义的:
# ./src/database/database_factory.py
engine = create_engine(current_app.config['SQLALCHEMY_DATABASE_URI'])
db_session = scoped_session(sessionmaker(autocommit=False,
autoflush=False,
bind=engine))
def init_db():
from database.models import Base, Table1, Table2, Table3, Table4
Base.metadata.create_all(bind=engine,
tables=[Table1.__table__, Table2.__table__, Table3.__table__, Table4.__table__])
@current_app.teardown_appcontext
def shutdown_session(exception=None):
db_session.remove()
我正在为这个应用编写一些测试,但在测试结束后,我遇到了一个问题,就是无法删除./tests/instance/test_db.sqlite
文件。我希望在通过一个fixture返回我的应用后,能够将其销毁,结构如下:
# ./tests/unit/conftest.py
@pytest.fixture()
def app():
app = create_app()
yield app
os.remove('./instance/test_db.sqlite')
测试失败,出现错误:“PermissionError: [WinError 32] 该进程无法访问文件,因为它正被另一个进程使用: './instance/test_db.sqlite'”
根据我的理解,在fixture中执行yield app
后,应用的上下文应该不再可用,因此scoped_session
也应该关闭。所以我不明白是什么导致了这个问题,我甚至不确定活跃的应用上下文是否是这个错误的原因。
我不确定这是否相关,但我的应用布局是这样的:
.
├── src/
│ ├── app_factory/
│ │ └── __init__.py
│ ├── database/
│ │ └── database_factory.py
│ └── instance/
│ └── test_db.sqlite
└── tests/
├── unit/
│ ├── conftest.py (this has fixtures)
│ └── test_db.py
└── instance/
└── test_db.sqlite (I want to delete this one as part of teardown)
sqlite3数据库是在实例文件夹中创建的,这个文件夹相对于create_app()
被调用的绝对路径(可能是在src或tests目录中)。
我找到了这个StackOverflow的帖子 Python PermissionError: [WinError 32] 该进程无法访问文件.....但我的文件是关闭的,我尝试在fixture的销毁部分明确关闭会话,像这样:
@pytest.fixture()
def app():
app = create_app()
yield app
from database.database_factory import db_session
db_session.close()
db_session.remove()
os.remove('./instance/test_db.sqlite')
但这也没有帮助。还有一点奇怪的是,在最后一个例子中,我可以在yield app
之后导入db_session
,因为在其他任何测试用例中,如果我尝试在应用上下文之外进行这个导入,测试都会失败。
请问有什么建议吗?
1 个回答
好的,我再查了一下,发现了这个帖子:https://stackoverflow.com/a/21742461/9280629
看起来问题不是出在关闭会话上,而是因为引擎连接还在活跃。一旦我用 dispose()
函数处理掉我的引擎,sqlite3 的数据库文件就可以成功删除了。